The most straightforward way to think about it is to think in terms of what type of object the method needs in order to do its work. If your method needs access to an instance, make it a regular method. If it needs access to the class, make it a classmethod. If it doesn't need access to the class or the instance, make it a function. There is rarely a need to make something a staticmethod, but if you find you want a function to be "grouped" with a class (e.g., so it can be overridden) even though it doesn't need access to the class, I guess you could make it a staticmethod.
I would add that putting functions at the module level doesn't "pollute" the namespace. If the functions are meant to be used, they're not polluting the namespace, they're using it just as it should be used. Functions are legitimate objects in a module, just like classes or anything else. There's no reason to hide a function in a class if it doesn't have any reason to be there.
Answer from BrenBarn on Stack OverflowCLASS & STATIC METHODS
python - Module function vs staticmethod vs classmethod vs no decorators: Which idiom is more pythonic? - Stack Overflow
oop - What is the difference between @staticmethod and @classmethod in Python? - Stack Overflow
@staticmethod vs @classmethod vs functions outside of class in Python - Software Engineering Stack Exchange
Videos
Hello everyone,
I was studying OOP and the concept of instances, class methods and static methods still confuses me.
I have watched tons of YouTube already but I can't find a person who explains it as dumb as possible because that is how I understand things.
Please if there is anyone who can recommend to me a video or explain it to me in the simplest way possible with examples, I will be glad :)
Note: I want the simplest form of explanation about the matter.
The most straightforward way to think about it is to think in terms of what type of object the method needs in order to do its work. If your method needs access to an instance, make it a regular method. If it needs access to the class, make it a classmethod. If it doesn't need access to the class or the instance, make it a function. There is rarely a need to make something a staticmethod, but if you find you want a function to be "grouped" with a class (e.g., so it can be overridden) even though it doesn't need access to the class, I guess you could make it a staticmethod.
I would add that putting functions at the module level doesn't "pollute" the namespace. If the functions are meant to be used, they're not polluting the namespace, they're using it just as it should be used. Functions are legitimate objects in a module, just like classes or anything else. There's no reason to hide a function in a class if it doesn't have any reason to be there.
Great answer by BrenBarn, but I would change 'If it doesn't need access to the class or the instance, make it a function' to:
'If it doesn't need access to the class or the instance...but is thematically related to the class (typical example: helper functions and conversion functions used by other class methods or used by alternate constructors), then use staticmethod
else make it a module function
Maybe a bit of example code will help: Notice the difference in the call signatures of foo, class_foo and static_foo:
class A(object):
def foo(self, x):
print(f"executing foo({self}, {x})")
@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")
@staticmethod
def static_foo(x):
print(f"executing static_foo({x})")
a = A()
Below is the usual way an object instance calls a method. The object instance, a, is implicitly passed as the first argument.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)
With classmethods, the class of the object instance is implicitly passed as the first argument instead of self.
a.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)
You can also call class_foo using the class. In fact, if you define something to be
a classmethod, it is probably because you intend to call it from the class rather than from a class instance. A.foo(1) would have raised a TypeError, but A.class_foo(1) works just fine:
A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)
One use people have found for class methods is to create inheritable alternative constructors.
With staticmethods, neither self (the object instance) nor cls (the class) is implicitly passed as the first argument. They behave like plain functions except that you can call them from an instance or the class:
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
Staticmethods are used to group functions which have some logical connection with a class to the class.
foo is just a function, but when you call a.foo you don't just get the function,
you get a "partially applied" version of the function with the object instance a bound as the first argument to the function. foo expects 2 arguments, while a.foo only expects 1 argument.
a is bound to foo. That is what is meant by the term "bound" below:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
With a.class_foo, a is not bound to class_foo, rather the class A is bound to class_foo.
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Here, with a staticmethod, even though it is a method, a.static_foo just returns
a good 'ole function with no arguments bound. static_foo expects 1 argument, and
a.static_foo expects 1 argument too.
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
And of course the same thing happens when you call static_foo with the class A instead.
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
A staticmethod is a method that knows nothing about the class or instance it was called on. It just gets the arguments that were passed, no implicit first argument.
A classmethod, on the other hand, is a method that gets passed the class it was called on, or the class of the instance it was called on, as first argument. This is useful when you want the method to be a factory for the class: since it gets the actual class it was called on as first argument, you can always instantiate the right class, even when subclasses are involved. Observe for instance how dict.fromkeys(), a classmethod, returns an instance of the subclass when called on a subclass:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
If your method calls a static method on the class, then it does require information on the class. You have a class method, not a static method. By declaring it @classmethod (and adding the cls parameter), you not only properly inform the reader, you allow polymorphism. An inheritor can reimplement the called static method and change behavior.
Python's static methods are intended for methods that are part of a class, and can be called as either a class method or an instance method: both Class.the_method() and self.the_method() would work. When the static method is called, it is not given an implicit first argument:
class Example:
def instance_method_example(self, arguments):
...
@classmethod
def class_method_example(cls, arguments):
...
@staticmethod
def static_method_example(arguments):
...
If you merely want to create a helper function that is used within your class, do not use @staticmethod. Define a free function outside of the class. For example:
class Example:
def some_method(self, argument):
return _helper(argument, self.x)
def _helper(a, b):
...
The background of static methods in Python is the following: when you access an attribute of an object x.attribute or getattr(x, 'attribute'), then this name is looked up in the instance dict or the class dict. If an object is found in the class dict, it is checked whether that object is a “descriptor”: an object that describes how this attribute behaves, not an object that would be directly returned. Descriptors have dunder-methods like __get__, __set__, and __del__ that are invoked depending on whether the descriptor is accessed, assigned to, or deleted with the del operator.
Functions – the things you declare with def – are descriptors. By default, the __get__ descriptor binds the function to the instance argument (typically called self) and returns the bound function, so that it can be invoked as a method. But the various decorators change this behaviour:
- a
@classmethod defbinds to the class object, not the instance - a
@staticmethod defdoes not bind to any object and just returns the underlying function directly - a
@propertyinvokes the underlying function to retrieve a value
These differences are (partially) visible when looking at the repr() of the bound methods. With the first Example class:
instance_method_example- with class:
Example.instance_method_example
is<function Example.instance_method_example at 0x7f1dfdd6fd30>,
the unbound function - with instance:
<function Example.instance_method_example at 0x7f1dfdd6fd30>
is<bound method Example.instance_method_example of <__main__.Example object at 0x7f1dfdddcb80>>,
a method bound to the instance
- with class:
class_method_example- with class:
Example.class_method_example
is<bound method Example.class_method_example of <class '__main__.Example'>>,
a method bound to the class - with instance:
Example().class_method_example
is<bound method Example.class_method_example of <class '__main__.Example'>>,
also a method bound to the class
- with class:
static_method_example- with class:
Example.static_method_example
is<function Example.static_method_example at 0x7f1dfdd6fe50>,
the unbound function - with instance:
Example().static_method_example
is<function Example.static_method_example at 0x7f1dfdd6fe50>,
also the unbound function
- with class:
As a table:
| invoked on… | no decorator | @classmethod |
@staticmethod |
|---|---|---|---|
| … instance | bound to instance | bound to class | unbound |
| … class | unbound | bound to class | unbound |