If you define a method inside a class, it is handled in a special way: access to it wraps it in a special object which modifies the calling arguments in order to include self
, a reference to the referred object:
class A(object):
def f(self):
pass
a = A()
a.f()
This call to a.f
actually asks f
(via the descriptor protocol) for an object to really return. This object is then called without arguments and deflects the call to the real f
, adding a
in front.
So what a.f()
really does is calling the original f
function with (a)
as arguments.
In order to prevent this, we can wrap the function
- with a
@staticmethod
decorator,
- with a
@classmethod
decorator,
- with one of other, similiar working, self-made decorators.
@staticmethod
turns it into an object which, when asked, changes the argument-passing behaviour so that it matches the intentions about calling the original f
:
class A(object):
def method(self):
pass
@staticmethod
def stmethod():
pass
@classmethod
def clmethod(cls):
pass
a = A()
a.method() # the "function inside" gets told about a
A.method() # doesn't work because there is no reference to the needed object
a.clmethod() # the "function inside" gets told about a's class, A
A.clmethod() # works as well, because we only need the classgets told about a's class, A
a.stmethod() # the "function inside" gets told nothing about anything
A.stmethod() # works as well
So @classmethod
and @staticmethod
have in common that they "don't care about" the concrete object they were called with; the difference is that @staticmethod
doesn't want to know anything at all about it, while @classmethod
wants to know its class.
So the latter gets the class object the used object is an instance of. Just replace self
with cls
in this case.
Now, when to use what?
Well, that is easy to handle:
- If you have an access to
self
, you clearly need an instance method.
- If you don't access
self
, but want to know about its class, use @classmethod
. This may for example be the case with factory methods. datetime.datetime.now()
is such an example: you can call it via its class or via an instance, but it creates a new instance with completely different data. I even used them once for automatically generating subclasses of a given class.
- If you need neither
self
nor cls
, you use @staticmethod
. This can as well be used for factory methods, if they don't need to care about subclassing.