What do @classmethod
and @staticmethod
mean in Python, and how are they different? When should I use them, why should I use them, and how should I use them?
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?
Though classmethod
and staticmethod
are quite similar, there's a slight difference in usage for both entities: classmethod
must have a reference to a class object as the first parameter, whereas staticmethod
can have no parameters at all.
class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
@classmethod
def from_string(cls, date_as_string):
day, month, year = map(int, date_as_string.split('-'))
date1 = cls(day, month, year)
return date1
@staticmethod
def is_date_valid(date_as_string):
day, month, year = map(int, date_as_string.split('-'))
return day <= 31 and month <= 12 and year <= 3999
date2 = Date.from_string('11-09-2012')
is_date = Date.is_date_valid('11-09-2012')
Let's assume an example of a class, dealing with date information (this will be our boilerplate):
class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
This class obviously could be used to store information about certain dates (without timezone information; let's assume all dates are presented in UTC).
Here we have __init__
, a typical initializer of Python class instances, which receives arguments as a typical instance method, having the first non-optional argument (self
) that holds a reference to a newly created instance.
Class Method
We have some tasks that can be nicely done using classmethod
s.
Let's assume that we want to create a lot of Date
class instances having date information coming from an outer source encoded as a string with format 'dd-mm-yyyy'. Suppose we have to do this in different places in the source code of our project.
So what we must do here is:
Date
by passing those values to the initialization call.This will look like:
day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
For this purpose, C++ can implement such a feature with overloading, but Python lacks this overloading. Instead, we can use classmethod
. Let's create another constructor.
@classmethod
def from_string(cls, date_as_string):
day, month, year = map(int, date_as_string.split('-'))
date1 = cls(day, month, year)
return date1
date2 = Date.from_string('11-09-2012')
Let's look more carefully at the above implementation, and review what advantages we have here:
cls
is the class itself, not an instance of the class. It's pretty cool because if we inherit our Date
class, all children will have from_string
defined also.Static method
What about staticmethod
? It's pretty similar to classmethod
but doesn't take any obligatory parameters (like a class method or instance method does).
Let's look at the next use case.
We have a date string that we want to validate somehow. This task is also logically bound to the Date
class we've used so far, but doesn't require instantiation of it.
Here is where staticmethod
can be useful. Let's look at the next piece of code:
@staticmethod
def is_date_valid(date_as_string):
day, month, year = map(int, date_as_string.split('-'))
return day <= 31 and month <= 12 and year <= 3999
# usage:
is_date = Date.is_date_valid('11-09-2012')
So, as we can see from usage of staticmethod
, we don't have any access to what the class is---it's basically just a function, called syntactically like a method, but without access to the object and its internals (fields and other methods), which classmethod
does have.
Answered 2023-09-21 08:08:43
classmethod
example, wouldn't you be able to do exactly what you did above by defining from_string
as a stringmethod
instead of as classmethod
, and then, instead of calling cls(day, month, year)
you would call Date(day, month, year)
? I suppose that the only benefit of using a classmethod
here would be if you would like that method to be available to subclasses who may inherit and expect from_string
to work for the inherited class right? Or did I miss anything your point? - anyone stringmethod
? Are you guys talking about staticmethod
? If so, I still don't understand why you can't use staticmethod
to accomplish the same thing as @Josh suggests. - anyone __init__()
is still a normal instancemethod
. The order of the functions inside the class definition does not matter. You can put the __init__()
as the last function and everything will still work the same. Usually, I would recommend putting it as the first function though, because anyone looking at the code will be able to immediately see how an instance of your class can be created. - anyone 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, 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
Answered 2023-09-21 08:08:43
@classmethod
is for. - anyone @classmethod
for factory methods that support inheritance: creating an instance of the calling class with some pre-processing etc. - anyone @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).
Answered 2023-09-21 08:08:43
@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.
@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)
.
here is good link to this topic.
Answered 2023-09-21 08:08:43
Meaning of
@classmethod
and@staticmethod
?
self
) as the implicit first argument.cls
) as the implicit first argument.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.)
A dotted lookup on an instance is performed in this order - we look for:
__dict__
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()
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>
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'>
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):
...
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'>
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.)
Answered 2023-09-21 08:08:43
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.)
Precisely what I was looking for. The actual why-I-would-use-it answer. - anyone 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..."
Answered 2023-09-21 08:08:43
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
Answered 2023-09-21 08:08:43
@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)
Answered 2023-09-21 08:08:43
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.Answered 2023-09-21 08:08:43
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.
Answered 2023-09-21 08:08:43
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.
Answered 2023-09-21 08:08:43
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)
Answered 2023-09-21 08:08:43