This has, in a way, a relationship with the attributes of instance and class, along with the construction of the Python language, more precisely the decorators. Unlike other languages, the definition of a static - or class method, using @classmethod
- is given through a decorator, not a language keyword. What does it change? It changes that when using a decorator over a method, the reference to this method is not directly accessible, because the decorator’s return 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 on Ideone | Repl.it
The exit will be:
<class 'function'>
<class 'function'>
And not method
, as expected. To better understand the behavior, just remember the functioning of a decorator: a function that returns another function (roughly speaking). 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 the @staticmethod
, but it becomes 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 since it is a class attribute, it keeps reference to the same object both in the class and in 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 on Ideone | Repl.it
The exit is something like:
47914624982008
47914624982008
Which indicates that objects accessed by the class or instance are exactly the same.
And why is it not past 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 implicitly defined 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 - is not passed such parameter (even because it makes no sense to access an instance in a static method).
We can imagine the staticmethod
as being something like:
def staticmethod(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
return wrapper
Note that on the call from func
, that would be the invocation (of evil) of the method, there is no equivalent parameter to self
being passed on.
But what if you need to access class attributes?
If within the method it is necessary to access class attributes it is not a static method we need, but a class method. Unlike the static method, the class method takes 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, different from @staticmethod
, in the @classmethod
there is the class passed as the first parameter. It would be something like:
def classmethod(func)
def wrapper(*args, **kwargs):
classObject = inspect.get_glass(func) # hipotético
func(classObject, *args, **kwargs)
return wrapper
I believe that it falls into the usual "because the language creators thought it was useful". It may be that they did not want to complicate the compiler. It may even be, although improbable, that they did not pay attention to it. There are those who think that this is not good because it is not the right intention. Tapping the eye looks like an instance method. But in languages like Python, it doesn’t care much about this. For example, you don’t know if `Person() is a constructor of any object or function. Language is not concerned with showing intention more clearly ,so this is considered normal in it.
– Maniero
Strangely, in Java it is also possible to call static methods through instances
– Artur Trapp
Here, Jon Skeet says he believes it was a mistake of the Java developers, maybe it also applies to Python (I dare not put it as a response haha)
– Artur Trapp
What I find strange is that in every nonstatic method in Python, the instance itself is passed as the first parameter of the method (self). Since the hello method does not receive any parameter, this should cause an error.
– flpn
I don’t know much about the particularities of Python, but is this self not passed anyway? Just as we have the
arguments
javascript– Artur Trapp
The self (which is actually the object that is trying to access the method) is implicitly passed to all methods. It may be that in the static methods this does not happen, another doubt that I have.
– flpn