Static methods in python date back to the introduction of the so-called “new-style classes” in Python 2.2. Previous to this, methods on classes were just ordinary functions, stored as attributes on the class:
class OldStyleClass:
def method(self):
print "'self' is just the first argument of this function"
instance = OldStyleClass()
OldStyleClass.method(instance) # Just an ordinary function call
print repr(OldStyleClass.method) # "unbound method..."
Method calls on instances were specially handled to automatically bind the instance to the first argument of the function:
instance.method() # 'instance' is automatically passed in as the first parameter
print repr(instance.method) # "bound method..."
In Python 2.2, much of the class system was rethought and reengineered as “new-style classes”—classes that inherit from object
. One of the features of new-style classes was “descriptors”, essentially an object in a class that is responsible for describing, getting, and setting the class's attributes. A descriptor has a __get__
method, that gets passed the class and the instance, and should return the requested attribute of the class or instance.
Descriptors made it possible to use a single API to implement complex behaviour for class attributes, like properties, class methods, and static methods. For example, the staticmethod
descriptor could be implemented like this:
class staticmethod(object):
"""Create a static method from a function."""
def __init__(self, func):
self.func = func
def __get__(self, instance, cls=None):
return self.func
Compare this with a hypothetical pure-python descriptor for an ordinary method, which is used by default for all plain functions in the classes attributes (this is not exactly what happens with method lookup from an instance, but it does handle the automatic 'self' argument):
class method(object):
"""Create a method from a function--it will get the instance
passed in as its first argument."""
def __init__(self, func):
self.func = func
def __get__(self, instance, cls=None):
# Create a wrapper function that passes the instance as first argument
# to the original function
def boundmethod(*args, **kwargs):
return self.func(self, *args, **kwargs)
return boundmethod
So when you write method = staticmethod(method)
, you are actually creating a new descriptor whose job it is to return the original function unchanged, and storing this descriptor in the class's "method" attribute.
If that seems like a lot of work to go to just to get the original function back—you’re right, it is. But since normal method calls are the default case, static methods and class methods need to be implemented separately, and descriptors give a way of enabling these and other complex behaviours with one simple API.
As others have already pointed out, the decorator syntax introduced in Python 2.4 gives a more convenient way of declaring static methods, but it is just a syntactic convenience, and doesn't change anything of how static methods work.
See http://www.python.org/doc/2.2.3/whatsnew/sect-rellinks.html and http://users.rcn.com/python/download/Descriptor.htm for more details on the new-style classes and descriptors.
self
. – Yoghurt