I've developed this short test/example code, in order to understand better how static methods work in Python.
class TestClass:
def __init__(self, size):
self.size = size
def instance(self):
print("regular instance method - with 'self'")
@staticmethod
def static():
print("static instance method - with @staticmethod")
def static_class():
print("static class method")
a = TestClass(1000)
a.instance()
a.static()
TestClass.static_class()
This code works correctly, it doesn't return any errors. My questions are:
Do I understand correctly that "self" can be understood as something like "this method will be called from an instance"?
Then again, what's the logic behind @staticmethod - is it to create static methods which can be called from an instance? Isn't that exactly not what static methods are about?
Why would the second approach be favored over the third one? (I assume that since the decorator exists, there is a point to this.) The 3rd option seems to be the simpler and more straightforward.
Here is a post on static methods. In summary:
Examples
It may be more clear to see how these work when called with arguments. A modified example:
class TestClass:
weight = 200 # class attr
def __init__(self, size):
self.size = size # instance attr
def instance_mthd(self, val):
print("Instance method, with 'self':", self.size*val)
@classmethod
def class_mthd(cls, val):
print("Class method, with `cls`:", cls.weight*val)
@staticmethod
def static_mthd(val):
print("Static method, with neither args:", val)
a = TestClass(1000)
a.instance_mthd(2)
# Instance method, with 'self': 2000
TestClass.class_mthd(2)
# Class method, with `cls`: 400
a.static_mthd(2)
# Static method, with neither args: 2
Notes
Overall, you can think of each method in terms of access:
self
as the first argument.In the example above, the same argument is passed for each method type, but access to instance and class attributes differ through self
and cls
respectively.
Note, there is a way to access class components from an instance method by using self.__class__
, thereby obviating the need for a class method:
...
def instance_mthd2(self, val):
print("Instance method, with class access via `self`:", self.__class__.weight*val)
...
a.instance_mthd2(2)
# Instance method, with class access via `self`: 400
Regarding your questions:
self
is a convention, it pertains to the instance.self
as the first argument or decorate the method with @staticmethod
. "Non-decorated methods" without arguments will raise an error.See Also