[python] Meaning of @classmethod and @staticmethod for beginner?

Could someone explain to me the meaning of @classmethod and @staticmethod in python? I need to know the difference and the meaning.

As far as I understand, @classmethod tells a class that it's a method which should be inherited into subclasses, or... something. However, what's the point of that? Why not just define the class method without adding @classmethod or @staticmethod or any @ definitions?

tl;dr: when should I use them, why should I use them, and how should I use them?

This question is related to python oop static-methods class-method

The answer is


Meaning of @classmethod and @staticmethod?

  • A method is a function in an object's namespace, accessible as an attribute.
  • A regular (i.e. instance) method gets the instance (we usually call it self) as the implicit first argument.
  • A class method gets the class (we usually call it cls) as the implicit first argument.
  • A static method gets no implicit first argument (like a regular function).

when should I use them, why should I use them, and how should I use them?

You don't need either decorator. But on the principle that you should minimize the number of arguments to functions (see Clean Coder), they are useful for doing just that.

class Example(object):

    def regular_instance_method(self):
        """A function of an instance has access to every attribute of that 
        instance, including its class (and its attributes.)
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_f(self)

    @classmethod
    def a_class_method(cls):
        """A function of a class has access to every attribute of the class.
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_g(cls)

    @staticmethod
    def a_static_method():
        """A static method has no information about instances or classes
        unless explicitly given. It just lives in the class (and thus its 
        instances') namespace.
        """
        return some_function_h()

For both instance methods and class methods, not accepting at least one argument is a TypeError, but not understanding the semantics of that argument is a user error.

(Define some_function's, e.g.:

some_function_h = some_function_g = some_function_f = lambda x=None: x

and this will work.)

dotted lookups on instances and classes:

A dotted lookup on an instance is performed in this order - we look for:

  1. a data descriptor in the class namespace (like a property)
  2. data in the instance __dict__
  3. a non-data descriptor in the class namespace (methods).

Note, a dotted lookup on an instance is invoked like this:

instance = Example()
instance.regular_instance_method 

and methods are callable attributes:

instance.regular_instance_method()

instance methods

The argument, self, is implicitly given via the dotted lookup.

You must access instance methods from instances of the class.

>>> instance = Example()
>>> instance.regular_instance_method()
<__main__.Example object at 0x00000000399524E0>

class methods

The argument, cls, is implicitly given via dotted lookup.

You can access this method via an instance or the class (or subclasses).

>>> instance.a_class_method()
<class '__main__.Example'>
>>> Example.a_class_method()
<class '__main__.Example'>

static methods

No arguments are implicitly given. This method works like any function defined (for example) on a modules' namespace, except it can be looked up

>>> print(instance.a_static_method())
None

Again, when should I use them, why should I use them?

Each of these are progressively more restrictive in the information they pass the method versus instance methods.

Use them when you don't need the information.

This makes your functions and methods easier to reason about and to unittest.

Which is easier to reason about?

def function(x, y, z): ...

or

def function(y, z): ...

or

def function(z): ...

The functions with fewer arguments are easier to reason about. They are also easier to unittest.

These are akin to instance, class, and static methods. Keeping in mind that when we have an instance, we also have its class, again, ask yourself, which is easier to reason about?:

def an_instance_method(self, arg, kwarg=None):
    cls = type(self)             # Also has the class of instance!
    ...

@classmethod
def a_class_method(cls, arg, kwarg=None):
    ...

@staticmethod
def a_static_method(arg, kwarg=None):
    ...

Builtin examples

Here are a couple of my favorite builtin examples:

The str.maketrans static method was a function in the string module, but it is much more convenient for it to be accessible from the str namespace.

>>> 'abc'.translate(str.maketrans({'a': 'b'}))
'bbc'

The dict.fromkeys class method returns a new dictionary instantiated from an iterable of keys:

>>> dict.fromkeys('abc')
{'a': None, 'c': None, 'b': None}

When subclassed, we see that it gets the class information as a class method, which is very useful:

>>> class MyDict(dict): pass
>>> type(MyDict.fromkeys('abc'))
<class '__main__.MyDict'> 

My advice - Conclusion

Use static methods when you don't need the class or instance arguments, but the function is related to the use of the object, and it is convenient for the function to be in the object's namespace.

Use class methods when you don't need instance information, but need the class information perhaps for its other class or static methods, or perhaps itself as a constructor. (You wouldn't hardcode the class so that subclasses could be used here.)


In short, @classmethod turns a normal method to a factory method.

Let's explore it with an example:

class PythonBook:
    def __init__(self, name, author):
        self.name = name
        self.author = author
    def __repr__(self):
        return f'Book: {self.name}, Author: {self.author}'

Without a @classmethod,you should labor to create instances one by one and they are scattered.

book1 = PythonBook('Learning Python', 'Mark Lutz')
In [20]: book1
Out[20]: Book: Learning Python, Author: Mark Lutz
book2 = PythonBook('Python Think', 'Allen B Dowey')
In [22]: book2
Out[22]: Book: Python Think, Author: Allen B Dowey

As for example with @classmethod

class PythonBook:
    def __init__(self, name, author):
        self.name = name
        self.author = author
    def __repr__(self):
        return f'Book: {self.name}, Author: {self.author}'
    @classmethod
    def book1(cls):
        return cls('Learning Python', 'Mark Lutz')
    @classmethod
    def book2(cls):
        return cls('Python Think', 'Allen B Dowey')

Test it:

In [31]: PythonBook.book1()
Out[31]: Book: Learning Python, Author: Mark Lutz
In [32]: PythonBook.book2()
Out[32]: Book: Python Think, Author: Allen B Dowey

See? Instances are successfully created inside a class definition and they are collected together.

In conclusion, @classmethod decorator convert a conventional method to a factory method,Using classmethods makes it possible to add as many alternative constructors as necessary.


A slightly different way to think about it that might be useful for someone... A class method is used in a superclass to define how that method should behave when it's called by different child classes. A static method is used when we want to return the same thing regardless of the child class that we are calling.


@classmethod means: when this method is called, we pass the class as the first argument instead of the instance of that class (as we normally do with methods). This means you can use the class and its properties inside that method rather than a particular instance.

@staticmethod means: when this method is called, we don't pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can't access the instance of that class (this is useful when your method does not use the instance).


@classmethod

@classmethod may be compared with __init__. You could think it is another __init__(). It is the way python realize class constructor overloading in c++.

class C:
    def __init__(self, parameters):
        ....

    @classmethod
    def construct_from_func(cls, parameters):
        ....

obj1 = C(parameters)
obj2 = C.construct_from_func(parameters)

notice they both has a reference for class as first argument in definitioin while __init__ use self but construct_from_func use cls conventionally.

@staticmethod

@staticmethod may be compared with object method

class C:
    def __init__(self):
        ....

    @staticmethod
    def static_method(args):
        ....

    def normal_method(parameters):
        ....

result = C.static_method(parameters)
result = obj.normal_method(parameters)

When to use each

@staticmethod function is nothing more than a function defined inside a class. It is callable without instantiating the class first. It’s definition is immutable via inheritance.

  • Python does not have to instantiate a bound-method for object.
  • It eases the readability of the code: seeing @staticmethod, we know that the method does not depend on the state of object itself;

@classmethod function also callable without instantiating the class, but its definition follows Sub class, not Parent class, via inheritance, can be overridden by subclass. That’s because the first argument for @classmethod function must always be cls (class).

  • Factory methods, that are used to create an instance for a class using for example some sort of pre-processing.
  • Static methods calling static methods: if you split a static methods in several static methods, you shouldn't hard-code the class name but use class methods

here is good link to this topic.


Rostyslav Dzinko's answer is very appropriate. I thought I could highlight one other reason you should choose @classmethod over @staticmethod when you are creating an additional constructor.

In the example above, Rostyslav used the @classmethod from_string as a Factory to create Date objects from otherwise unacceptable parameters. The same can be done with @staticmethod as is shown in the code below:

class Date:
  def __init__(self, month, day, year):
    self.month = month
    self.day   = day
    self.year  = year


  def display(self):
    return "{0}-{1}-{2}".format(self.month, self.day, self.year)


  @staticmethod
  def millenium(month, day):
    return Date(month, day, 2000)

new_year = Date(1, 1, 2013)               # Creates a new Date object
millenium_new_year = Date.millenium(1, 1) # also creates a Date object. 

# Proof:
new_year.display()           # "1-1-2013"
millenium_new_year.display() # "1-1-2000"

isinstance(new_year, Date) # True
isinstance(millenium_new_year, Date) # True

Thus both new_year and millenium_new_year are instances of the Date class.

But, if you observe closely, the Factory process is hard-coded to create Date objects no matter what. What this means is that even if the Date class is subclassed, the subclasses will still create plain Date objects (without any properties of the subclass). See that in the example below:

class DateTime(Date):
  def display(self):
      return "{0}-{1}-{2} - 00:00:00PM".format(self.month, self.day, self.year)


datetime1 = DateTime(10, 10, 1990)
datetime2 = DateTime.millenium(10, 10)

isinstance(datetime1, DateTime) # True
isinstance(datetime2, DateTime) # False

datetime1.display() # returns "10-10-1990 - 00:00:00PM"
datetime2.display() # returns "10-10-2000" because it's not a DateTime object but a Date object. Check the implementation of the millenium method on the Date class for more details.

datetime2 is not an instance of DateTime? WTF? Well, that's because of the @staticmethod decorator used.

In most cases, this is undesired. If what you want is a Factory method that is aware of the class that called it, then @classmethod is what you need.

Rewriting Date.millenium as (that's the only part of the above code that changes):

@classmethod
def millenium(cls, month, day):
    return cls(month, day, 2000)

ensures that the class is not hard-coded but rather learnt. cls can be any subclass. The resulting object will rightly be an instance of cls.
Let's test that out:

datetime1 = DateTime(10, 10, 1990)
datetime2 = DateTime.millenium(10, 10)

isinstance(datetime1, DateTime) # True
isinstance(datetime2, DateTime) # True


datetime1.display() # "10-10-1990 - 00:00:00PM"
datetime2.display() # "10-10-2000 - 00:00:00PM"

The reason is, as you know by now, that @classmethod was used instead of @staticmethod


Class method can modify the class state,it bound to the class and it contain cls as parameter.

Static method can not modify the class state,it bound to the class and it does't know class or instance

class empDetails:
    def __init__(self,name,sal):
        self.name=name
        self.sal=sal
    @classmethod
    def increment(cls,name,none):
        return cls('yarramsetti',6000 + 500)
    @staticmethod
    def salChecking(sal):
        return sal > 6000

emp1=empDetails('durga prasad',6000)
emp2=empDetails.increment('yarramsetti',100)
# output is 'durga prasad'
print emp1.name
# output put is 6000
print emp1.sal
# output is 6500,because it change the sal variable
print emp2.sal
# output is 'yarramsetti' it change the state of name variable
print emp2.name
# output is True, because ,it change the state of sal variable
print empDetails.salChecking(6500)

I'm a beginner on this site, I have read all above answers, and got the information what I want. However, I don't have the right to upvote. So I want to get my start on StackOverflow with the answer as I understand it.

  • @staticmethod doesn't need self or cls as the first parameter of the method
  • @staticmethod and @classmethod wrapped function could be called by instance or class variable
  • @staticmethod decorated function impact some kind 'immutable property' that subclass inheritance can't overwrite its base class function which is wrapped by a @staticmethod decorator.
  • @classmethod need cls (Class name, you could change the variable name if you want, but it's not advised) as the first parameter of function
  • @classmethod always used by subclass manner, subclass inheritance may change the effect of base class function, i.e. @classmethod wrapped base class function could be overwritten by different subclasses.

One would use @classmethod when he/she would want to change the behaviour of the method based on which subclass is calling the method. remember we have a reference to the calling class in a class method.

While using static you would want the behaviour to remain unchanged across subclasses

Example:

class Hero:

  @staticmethod
  def say_hello():
     print("Helllo...")

  @classmethod
  def say_class_hello(cls):
     if(cls.__name__=="HeroSon"):
        print("Hi Kido")
     elif(cls.__name__=="HeroDaughter"):
        print("Hi Princess")

class HeroSon(Hero):
  def say_son_hello(self):
     print("test  hello")



class HeroDaughter(Hero):
  def say_daughter_hello(self):
     print("test  hello daughter")


testson = HeroSon()

testson.say_class_hello() #Output: "Hi Kido"

testson.say_hello() #Outputs: "Helllo..."

testdaughter = HeroDaughter()

testdaughter.say_class_hello() #Outputs: "Hi Princess"

testdaughter.say_hello() #Outputs: "Helllo..."

A little compilation

@staticmethod A way to write a method inside a class without reference to the object it is being called on. So no need to pass implicit argument like self or cls. It is written exactly the same how written outside the class, but it is not of no use in python because if you need to encapsulate a method inside a class since this method needs to be the part of that class @staticmethod is comes handy in that case.

@classmethod It is important when you want to write a factory method and by this custom attribute(s) can be attached in a class. This attribute(s) can be overridden in the inherited class.

A comparison between these two methods can be as below

Table


Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to oop

How to implement a simple scenario the OO way When to use 'raise NotImplementedError'? PHP: cannot declare class because the name is already in use Python class input argument Call an overridden method from super class in typescript Typescript: How to extend two classes? What's the difference between abstraction and encapsulation? An object reference is required to access a non-static member Java Multiple Inheritance Why not inherit from List<T>?

Examples related to static-methods

How to verify static void method has been called with power mockito Calling class staticmethod within the class body? Meaning of @classmethod and @staticmethod for beginner? Difference between Static methods and Instance methods How can I solve "Non-static method xxx:xxx() should not be called statically in PHP 5.4? How to call getClass() from a static method in Java? Cannot make a static reference to the non-static method calling another method from the main method in java When to use static methods Why doesn't Java allow overriding of static methods?

Examples related to class-method

Meaning of @classmethod and @staticmethod for beginner? How to make a class property? Ruby: Calling class method from instance Calling C++ class methods via a function pointer What is the difference between class and instance methods? What is the purpose of class methods?