When studying Python, you inevitably face the problem of choosing between static methods (@staticmethod
), class methods (@classmethod
), and module-level
functions. In this article, I would like to deal with this issue.
From a technical point of view, the only difference between static and class methods is that the class method gets the class as the first argument.
Consider a simple example:
class Number:
def __init__(self, value):
self.value = value
@classmethod
def multiply(cls, x, y):
return cls(x*y)
@staticmethod
def divide(x, y):
return Number(x // y)
In this example, the Number class has two methods: a class method multiply
and a static one divide
. And we can successfully call both of these methods and it will all work.
>>> n = Number.multiply(1, 2)
>>> n.print()
2
>>> type(n)
<class '__main__.Number'>
>>> n = Number.divide(2, 1)
>>> n.print()
2
>>> type(n)
<class '__main__.Number'>
But what will happen if an inheritance is used?
For example:
class Real(Number):
pass
The class Real
will inherit all the methods of Number
, but when we access the divide
method, we will not get exactly what we might expect.
>>> r = Real.multiply(1, 2)
>>> r.print()
2
>>> type(r)
<class '__main__.Real'>
>>> r = Real.divide(2, 1)
>>> r.print()
2
>>>type(r)
<class '__main__.Number'>
As we can see, the divide
method will return a Number
instance instead of Real
. To solve this problem, @classmethod
-s are just right.
class Number:
def __init__(self, value):
self.value = value
@classmethod
def divide(cls, x, y):
return cls(x // y)
def print(self):
print(self.value)
class Real(Number): pass
>>> r = Real.divide(2, 1)
>>> r.print()
2
>>>type(r)
<class '__main__.Real'>
I believe that if a function needs access to a class, then it is a class method, if it does not need access to either the class or an instance of the class, but is logically related to the class, then it is a static method, otherwise, it is a module-level function.