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.
Example
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')
Explanation
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 classmethods.
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:
- Parse a string to receive day, month and year as three integer variables or a 3-item tuple consisting of that variable.
- Instantiate
Dateby 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:
- We've implemented date string parsing in one place and it's reusable now.
- Encapsulation works fine here (if you think that you could implement string parsing as a single function elsewhere, this solution fits the OOP paradigm far better).
clsis the class itself, not an instance of the class. It's pretty cool because if we inherit ourDateclass, all children will havefrom_stringdefined 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.
python - Meaning of @classmethod and @staticmethod for a beginner - Stack Overflow
What is @classmethod in python and why we need this , when to use it?
terminology - What are "class methods" and "instance methods", in Python? - Software Engineering Stack Exchange
When to Use Class Methods vs. Functions?
Videos
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.
Example
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')
Explanation
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 classmethods.
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:
- Parse a string to receive day, month and year as three integer variables or a 3-item tuple consisting of that variable.
- Instantiate
Dateby 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:
- We've implemented date string parsing in one place and it's reusable now.
- Encapsulation works fine here (if you think that you could implement string parsing as a single function elsewhere, this solution fits the OOP paradigm far better).
clsis the class itself, not an instance of the class. It's pretty cool because if we inherit ourDateclass, all children will havefrom_stringdefined 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.
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
The short answer
- an instance method knows its instance (and from that, its class)
- a class method knows its class
- a static method doesn't know its class or instance
The long answer
Class methods
A class method is one that belongs to the class as a whole. It doesn't require an instance. Instead, the class will automatically be sent as the first argument. A class method is declared with the @classmethod decorator.
For example:
class Foo(object):
@classmethod
def hello(cls):
print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"
Instance Methods
On the other hand, an instance method requires an instance in order to call it, and requires no decorator. This is by far the most common type of method.
class Foo(object):
def hello(self):
print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'
(note: the above is with python3; with python2 you'll get a slightly different error)
Static methods
A static method is similar to a class method, but won't get the class object as an automatic parameter. It is created by using the @staticmethod decorator.
class Foo(object):
@staticmethod
def hello(cls):
print("hello from %s" % cls.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'
Documentation links
Here are links to the relevant python3 documentaton:
- https://docs.python.org/3.5/library/functions.html#classmethod
- https://docs.python.org/3.5/library/functions.html#staticmethod
The data model documentation has this to say about the difference between class methods and static methods:
Static method objects Static method objects provide a way of defeating the transformation of function objects to method objects described above. A static method object is a wrapper around any other object, usually a user-defined method object. When a static method object is retrieved from a class or a class instance, the object actually returned is the wrapped object, which is not subject to any further transformation. Static method objects are not themselves callable, although the objects they wrap usually are. Static method objects are created by the built-in staticmethod() constructor.
Class method objects A class method object, like a static method object, is a wrapper around another object that alters the way in which that object is retrieved from classes and class instances. The behaviour of class method objects upon such retrieval is described above, under “User-defined methods”. Class method objects are created by the built-in classmethod() constructor.
Related questions
- What is the difference between @staticmethod and @classmethod in Python? (stackoverflow)
What are “class methods” and “instance methods”, in Python?
An "instance method" uses the information contained in the instance to figure out what value to return (or which side-effect to do). These are very common.
A "class method" uses information about the class (and not an instance of that class) to affect what it does (they're typically used to create new instances as alternative constructors, and thus aren't incredibly common).
A "static method" doesn't use any information about the class or instance to calculate what it does. It is usually just in the class for convenience. (As such, these aren't very common either.)
A Function of X
Remember math class, "y is a function of x, f(x)?" Let's apply that in code:
y = function(x)
Implied by the above is that since x may change, y may change when x changes. This is what is meant when we say that "y is a function of x"
What will y be when z is 1? 2? 'FooBarBaz'?
y is not a function of z, so z can be anything and not affect the outcome of the function assuming our function is a pure function. (If it accesses z as a global variable, then it's not a pure function - this is what is meant by functional purity.)
Keep the above in mind as you read the following descriptions:
Instance Methods
An instance method is function that is a function of an instance. The function accepts the instance implicitly as an argument to it, and the instance is used by the function to determine the output of the function.
A built-in example of an instance method is str.lower:
>>> 'ABC'.lower()
'abc'
str.lower is implicitly called on the instance of the string, and it uses the information contained in the instance to figure out which new string to return.
We can also explicitly pass the instance to the method looked up from the str class:
>>> str.lower('ABC')
'abc'
Class Methods:
Remember, in Python, everything is an object. That means the class is an object, and can be passed as an argument to a function.
A class method is a function that is a function of the class. It accepts the class as an argument to it.
A builtin example is dict.fromkeys:
>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}
The function implicitly knows its own class, the function uses the class to affects the output of the function, and it creates a new one of that class from the iterable. An OrderedDict demonstrates this when using the same method:
>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])
The class method uses information about the class (and not an instance of that class) to affect what type of class to return.
We can also look up the method directly from the class namespace (a simple dictionary) and pass the class object explicitly:
>>> vars(dict)'fromkeys'
{'A': None, 'B': None, 'C': None}
>>> vars(dict)'fromkeys'
OrderedDict([('A', None), ('B', None), ('C', None)])
Static Methods
You mention a method that "doesn't know its class" - this is a static method in Python. It is merely attached for convenience to the class object. It could optionally be a separate function in another module, but its call signature would be the same.
A static method is a function of neither the class nor the object.
A built-in example of a static method is str.maketrans from Python 3.
>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}
Given a couple of arguments, it makes a dictionary that is not a function of its class.
It is convenient because str is always available in the global namespace, so you can easily use it with the translate function:
>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'
In Python 2, you have to access it from the string module:
>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'
And now, in Python 3.10, thanks to issue 43682 being resolved, we can indeed simply look up the method/function in the class namespace and use it as a function:
>>> vars(str)'maketrans'
{97: 65, 98: 66, 99: 67}
Example
class AClass(object):
"""In Python, a class may have several types of methods:
instance methods, class methods, and static methods
"""
def an_instance_method(self, x, y, z=None):
"""this is a function of the instance of the object
self is the object's instance
"""
return self.a_class_method(x, y)
@classmethod
def a_class_method(cls, x, y, z=None):
"""this is a function of the class of the object
cls is the object's class
"""
return cls.a_static_method(x, y, z=z)
@staticmethod
def a_static_method(x, y, z=None):
"""this is neither a function of the instance or class to
which it is attached
"""
return x, y, z
Let's instantiate:
>>> instance = AClass()
Now the instance can call all of the methods:
>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)
But the class is not usually intended to call the instance method, though it is expected to call the others:
>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'
You would have to explicitly pass the instance to call the instance method:
>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)