Static methods in Python?
Solution 1:
Yep, using the staticmethod decorator
class MyClass(object):
@staticmethod
def the_static_method(x):
print(x)
MyClass.the_static_method(2) # outputs 2
Note that some code might use the old method of defining a static method, using staticmethod
as a function rather than a decorator. This should only be used if you have to support ancient versions of Python (2.2 and 2.3)
class MyClass(object):
def the_static_method(x):
print(x)
the_static_method = staticmethod(the_static_method)
MyClass.the_static_method(2) # outputs 2
This is entirely identical to the first example (using @staticmethod
), just not using the nice decorator syntax
Finally, use staticmethod
sparingly! There are very few situations where static-methods are necessary in Python, and I've seen them used many times where a separate "top-level" function would have been clearer.
The following is verbatim from the documentation::
A static method does not receive an implicit first argument. To declare a static method, use this idiom:
class C: @staticmethod def f(arg1, arg2, ...): ...
The @staticmethod form is a function decorator – see the description of function definitions in Function definitions for details.
It can be called either on the class (such as
C.f()
) or on an instance (such asC().f()
). The instance is ignored except for its class.Static methods in Python are similar to those found in Java or C++. For a more advanced concept, see
classmethod()
.For more information on static methods, consult the documentation on the standard type hierarchy in The standard type hierarchy.
New in version 2.2.
Changed in version 2.4: Function decorator syntax added.
Solution 2:
I think that Steven is actually right. To answer the original question, then, in order to set up a class method, simply assume that the first argument is not going to be a calling instance, and then make sure that you only call the method from the class.
(Note that this answer refers to Python 3.x. In Python 2.x you'll get a TypeError
for calling the method on the class itself.)
For example:
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
def rollCall(n): #this is implicitly a class method (see comments below)
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
In this code, the "rollCall" method assumes that the first argument is not an instance (as it would be if it were called by an instance instead of a class). As long as "rollCall" is called from the class rather than an instance, the code will work fine. If we try to call "rollCall" from an instance, e.g.:
rex.rollCall(-1)
however, it would cause an exception to be raised because it would send two arguments: itself and -1, and "rollCall" is only defined to accept one argument.
Incidentally, rex.rollCall() would send the correct number of arguments, but would also cause an exception to be raised because now n would be representing a Dog instance (i.e., rex) when the function expects n to be numerical.
This is where the decoration comes in: If we precede the "rollCall" method with
@staticmethod
then, by explicitly stating that the method is static, we can even call it from an instance. Now,
rex.rollCall(-1)
would work. The insertion of @staticmethod before a method definition, then, stops an instance from sending itself as an argument.
You can verify this by trying the following code with and without the @staticmethod line commented out.
class Dog:
count = 0 # this is a class variable
dogs = [] # this is a class variable
def __init__(self, name):
self.name = name #self.name is an instance variable
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n): # this is an instance method
print("{} says: {}".format(self.name, "woof! " * n))
@staticmethod
def rollCall(n):
print("There are {} dogs.".format(Dog.count))
if n >= len(Dog.dogs) or n < 0:
print("They are:")
for dog in Dog.dogs:
print(" {}".format(dog))
else:
print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)
Solution 3:
Yes, check out the staticmethod decorator:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World