It is possible to define two kinds of methods within a Python class that can be called without an object instance:
- static methods
- class methods
class MyClass:
def instance_method(self):
return 'instance method called', self
@classmethod
def class_method(cls):
return 'class method called', cls
@staticmethod
def static_method():
return 'static method called'
cls = MyClass()
print(cls.instance_method())
# class methods can be called with or without an instance
print(cls.class_method())
print(MyClass.class_method())
# static methods can be called with or without an instance
print(cls.static_method())
print(MyClass.static_method())
# outputs:
('instance method called', <__main__.MyClass object at 0x7f8acf550490>)
('class method called', <class '__main__.MyClass'>)
('class method called', <class '__main__.MyClass'>)
static method called
static method called
Class methods are typically less commonly used, whereas static method are often used to provide class based services. For example, one of the recommended practices in clean coding is to avoid too many overloaded constructors. The simplest way to achieve that is to provide class factory methods. Factory methods are static methods which accept a number of arguments and return an initialised object instance. They are typically named according to how they initialise the object.
Here’s a very contrived example of how we might implement factory methods in Python:
from collections import namedtuple
class Employee:
def __init__(self, firstname, lastname, employee_id):
self.firstname = firstname
self.lastname = lastname
self.employee_id = employee_id
def __str__(self):
return f'{self.firstname}, {self.lastname}, {self.employee_id}'
@staticmethod
def from_employee(e):
return Employee(e.firstname, e.lastname, e.employee_id)
@staticmethod
def from_new_hire(p):
return Employee(p.given, p.surname, p.hire_id)
NewHire = namedtuple('NewHire', 'given surname hire_id')
hire = NewHire(given='gill', surname='smith', hire_id='1234')
employee = Employee('fred', 'blogs', '789')
bob = Employee("bob", "jones", "123")
fred = Employee.from_employee(employee)
gill = Employee.from_new_hire(hire)
print(bob)
print(fred)
print(gill)
# outputs:
bob, jones, 123
fred, blogs, 789
gill, smith, 1234
So the three types of methods you can use in Python are:
- instance methods that modify instance and class state. They accept self as an argument
- class methods that modify class state, accept a class, and have a @classmethod annotation
- static that methods cannot modify state, and are annotated with @staticmethod
Here’s an example I modified slightly from the RealPython website, using class methods:
class Pizza:
_numInstances = 0
def __init__(self, ingredients):
Pizza._numInstances += 1
self.ingredients = ingredients
def __repr__(self):
return f'Pizza({self.ingredients})'
@classmethod
def margherita(cls):
return cls(['cheese', 'tomatoes'])
@classmethod
def procuitoo(cls):
return cls(['cheese', 'tomatoes', 'ham', 'mushrooms'])
@classmethod
def number_pizzas_made(cls):
return cls._numInstances
print(Pizza.margherita())
print(Pizza.procuitoo())
print(Pizza.number_pizzas_made())
# outputs:
Pizza(['cheese', 'tomatoes'])
Pizza(['cheese', 'tomatoes', 'ham', 'mushrooms'])
2
Lastly, an example of a simple static method:
import math
class Math:
@staticmethod
def circle_area(r):
return r ** 2 * math.pi
print(Math.circle_area(10))
# outputs:
314.1592653589793