This has some relation to the instance and class attributes, along with the construction of the Python language, more precisely the decorators. Unlike other languages, the definition of a static method - or class, using @classmethod
- is done through a decorator, not a language key word. What does that change? It changes that when using a decorator on a method, the reference to this method is not directly accessible, since the return of the decorator is a function - and it is this function that invokes the method reference. You can confirm this by doing:
class Person:
@staticmethod
def hello():
print('Hello!')
print(type(Person.hello))
print(type(Person().hello))
See working at Ideone | Repl.it
The output will be:
<class 'function'>
<class 'function'>
And not method
, as expected. To better understand the behavior, just remember the operation of a decorator: a function that returns another function (roughly). So much so that it is possible to call the decorator explicitly.
class Person:
def __hello():
print('Hello!')
hello = staticmethod(__hello)
This code, for practical purposes, is equivalent to the previous one, which uses @staticmethod
, but it is clear that what is created is a class attribute called hello
, which is a function, return of the decorator . Being a class attribute, it will also be accessible in instances - and because it is a class attribute, it maintains the reference to the same object in both the class and the instance. We can confirm this by checking the id
of each:
class Person:
@staticmethod
def hello():
print('Hello!')
print(id(Person.hello))
print(id(Person().hello))
See working at Ideone | Repl.it
Output is something like:
47914624982008
47914624982008
This indicates that objects accessed by the class or instance are exactly the same.
And why is not self
per parameter?
Precisely because the object does not point to a method, but rather to a function (which is the return of the decorator). The first parameter, self
, is defined implicitly in the call of a method by Python, however, as in this case what happens is the call of a function - and it is the function that invokes the method - no such parameter is passed. because it does not make sense to access an instance in a static method).
We can imagine staticmethod
as something like:
def staticmethod(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
Notice that in the call of func
, which would be the invocation ( of evil ) method, there is no parameter equivalent to self
being passed.
But what if you need to access class attributes?
If within the method it is necessary to access the class attributes it is not a static method that we need, but rather a class method. Unlike the static method, the class method receives as its first parameter an object that is the reference to the class itself:
class Person:
attr = "SOpt"
@classmethod
def hello(cls):
print('Hello', cls.attr)
This happens because, unlike @staticmethod
, in @classmethod
, there is the class pass as the first parameter. It would look something like:
def classmethod(func)
def wrapper(*args, **kwargs):
classObject = inspect.get_glass(func) # hipotético
func(classObject, *args, **kwargs)
return wrapper