views:

4966

answers:

4

What is the difference between a function decorated with @staticmethod and one decorated with @classmethod?

+46  A: 

A staticmethod is a method that knows nothing about the class or instance it was called on. It just gets the arguments that were passed, no implicit first argument. It is basically useless in Python -- you can just use a module function instead of a staticmethod.

A classmethod, on the other hand, is a method that gets passed the class it was called on, or the class of the instance it was called on, as first argument. This is useful when you want the method to be a factory for the class: since it gets the actual class it was called on as first argument, you can always instantiate the right class, even when subclasses are involved. Observe for instance how dict.fromkeys(), a classmethod, returns an instance of the subclass when called on a subclass:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
Thomas Wouters
A staticmethod isn't useless - it's a way of putting a function into a class (because it logically belongs there), while indicating that it does not require access to the class.
Tony Meyer
Hence only 'basically' useless. Such organization, as well as dependency injection, are valid uses of staticmethods, but since modules, not classes like in Java, are the basic elements of code organization in Python, their use and usefulness is rare.
Thomas Wouters
What's logical about defining a method inside a class, when it has nothing to do with either the class or its instances?
Ben James
Perhaps for the inheritance sake? Static methods can be inherited and overridden just like instance methods and class methods and the lookup works as expected (unlike in Java). Static methods are not really resolved statically whether called on the class or instance, so the only difference between class and static methods is the implicit first argument.
haridsv
+7  A: 

Basically @classmethod makes a method who's first argument is the class it's called from (rather than the class instance), @staticmethod does not have any implicit arguments.

Terence Simpson
A: 

@staticmethod just disables the default function as method descriptor. classmethod wraps your function in a container callable that passes a reference to the owning class as first argument:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

As a matter of fact, classmethod has a runtime overhead but makes it possible to access the owning class. Alternatively I recommend using a metaclass and putting the class methods on that metaclass:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>
Armin Ronacher
Man, recommending a metaclass is like, the worst answer I've seen on stackoverflow yet.
Jerub
What's the problem with a metaclass?
Armin Ronacher
What are the advantages to using a metaclass for this?
Daryl Spitzer
A: 

Staticmethod is not useless. since it is not passed an implicit class or instance of class as first argument, it is useful for processing class attributes that spans instances.

Eric Wang