Reputation: 461
I made these two classes:
class A:
@staticmethod
def f(x):
print("x is", x)
class B:
def f(x):
print("x is", x)
And used them like this:
>>> A.f(1)
x is 1
>>> B.f(1)
x is 1
It looks like f
became a static method on B even without the decorator. Why would I need the decorator?
Upvotes: 14
Views: 7579
Reputation: 2503
The OP's invocation:
A.f(1)
B.f(1)
are examples of Class Attribute references, where the attribute in these cases is the method f()
of the class A
(@staticmethod) and the method f()
(non static) of the class B
.
As showed below, the execution of these invocations gives different output for Python2 and Python3.
With Python 2.7.17 the execution of the code of the OP gives the following output:
>>> from classdef import A, B
>>> A.f(1)
('x is', 1)
>>> B.f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with B instance as first argument (got int instance instead)
This output shows that with Python2 the decorator @staticmethod (present only in the method f
of the class A
) is able to avoid the runtime error.
With Python 3.6.9 the execution of the code of the OP gives the following output:
>>> from classdef import A,B
>>> A.f(1)
x is 1
>>> B.f(1)
x is 1
So the OP uses a Python3 interpreter which gives the same result with or without the decorator @staticmethod.
@staticmethod
works with instance of a class (the same for Python2 and Python3)The following information are true for Python2 and Python3.
As explained in an other answer, the @staticmethod
decorator causes that (when the method is called) it is not passed to it a reference to the object use for the calling. This means that you must explicitly pass it a correct reference.
In the following code example is showed how to call a staticmethod
of a class by a reference to an instance of the class:
class MyClass:
attributeMyClass = "this is a Class attribute"
def __init__(self):
self.attributeMyClass = "this is an instance attribute"
@staticmethod
def show_attribute(self):
print(self.attributeMyClass)
# x is an instance of the class MyClass
x = MyClass()
# the argument is a MyClass object
x.show_attribute(MyClass)
# the argument is an instance of the class MyClass
x.show_attribute(x)
The output of the code execution is:
this is a Class attribute
this is an instance attribute
The print()
instruction of the staticmethod show_attribute()
prints a different variable in the two calls.
Upvotes: 0
Reputation: 26372
Try these two classes, both having a cry
method, one as a classmethod and another as a staticmethod with self
passed on
class Cat:
def __init__(self):
self.sound = "meow"
def cry(self):
print(self.sound)
x = Cat()
x.cry()
meow
and with another class
class Dog:
def __init__(self):
self.sound = "ruff-ruff"
@staticmethod
def cry(self):
print(self.sound)
x = Dog()
x.cry()
TypeError: cry() missing 1 required positional argument: 'self'
and we can see the @staticmethod
decorator basically removed the passed in self
Upvotes: 4
Reputation: 280227
It used to matter more back in Python 2, where the instance-ness of instance methods was enforced more strongly:
>>> class B:
... def f(x):
... print("x is", x)
...
>>> B.f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with B instance as first argument (
got int instance instead)
You had to mark static methods with @staticmethod
back then.
These days, @staticmethod
still makes it clearer that the method is static, which helps with code readability and documentation generation, and it lets you call the method on instances without the system trying to bind self
.
Upvotes: 10