Object-oriented programming in Python is far from being perfect. There are, however, some built-in functions that help programmers achieve OOP as we can find in truly OOP languages like Java or C#. Today I will try to clarify the purpose of two built-in decorators that are widely used in the context of OOP: @staticmethod and @classmethod.

Let’s consider the example below of an Example python class, with a method (method), a static method (static_method) and a class method (class_method).

class Example:
    def method(self, param):
       print(self, param) 

    def static_method(param):

    def class_method(cls, param):
       print(cls, param) 
  • method: usual class method, it will implicitly receive the instance of the class as the first argument (self) of the method.

    Example().method('text') # <__main__.Example object at 0x11044be80> text
  • static_method: a static method doesn’t receive an implicit first argument. It can be called with an instance of the class or the class itself. Static methods in python behave just like any other module function, except that they are now part of the class context. It’s like putting a function into a class since it may logically belong there, while indicating that the method doesn’t require access to the class.

    Example.static_method('text')   # text
    Example().static_method('text') # text 
  • class_method: among the three, the class method is the least common. It will implicitly receive the class (cls) as the first argument. While an instance method receives the instance of the class, the class method will always receive the class itself whether it was called through the class or an instance of the class.

    Example.class_method('text')   # <class '__main__.Example'> text
    Example().class_method('text') # <class '__main__.Example'> text

    Class methods are commonly used as factory methods, e.g.

    class Example:
        def __init__(self, text):
            self.text = text
        def from_string(cls, text):
            return cls(text)
    example = Example.from_string("hello world")
    print(example.text) # hello world