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'](dict, 'ABC')
{'A': None, 'B': None, 'C': None}
>>> vars(dict)['fromkeys'](OrderedDict, 'ABC')
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']('abc', 'ABC')
{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)