Working with Instance, Class and Static Methods

November 21, 2021

Overview

Python's instance, class and static methods allow you to build intuitive object-orientated classes that help convey developer intent. An example class containing all method types looks like this:

class Methods:
    def instance_method(self):
        ...
 
    @classmethod
    def class_method(cls):
        ...
 
    @staticmethod
    def static_method():
        ...

Instance Method

  • The default method of a class (does not use any decorator)
  • Receives the caller object as a special first parameter (usually named self, but this can be anything you want)
  • Bound to the instance of the class (requires a class object to be created)
  • Has access to class state and instance state
  • Usage:
    • Useful when you need access to class state and instance state

Class Method

  • Uses the @classmethod decorator
  • Receives the caller class as a special first parameter (usually named cls, but this can be anything you want)
  • Bound to the class (doesn't require a class object to be created)
  • Has access to class state but not instance state
  • Usage:
    • Useful when you need access to class state only
    • Help create instances of a class with pre-defined characteristics (alternative constructors)
    • Automatically use the sub-class in an inheritance scenario (remember, a class method receives the caller class)

Static Method

  • Uses the @staticmethod decorator
  • Does not receive the caller object or the caller class as a special first parameter
  • Not bound to the instance of the class or the class itself (doesn't require a class object to be created)
  • Does not have access to class state or instance state
  • Usage:
    • Useful to communicate developer intent that the method won't modify class or instance state
    • Couple the method to the class namespace
    • Perform generic / default operations
    • Testing doesn't require an instance of a class, simply test the method like you would any other function

Object State and Class State

Alter State with Instance Methods

An instance method receives the caller object and may alter object state and class state.

  • To alter object state, the instance method makes use of the self parameter
  • To alter class state for the instance, the instance method makes use of the self parameter and calls on the class attribute
  • To alter class state for the class, the instance method makes use of the self parameter and calls on the class attribute with __class__

For example:

class MyClass:
    class_name = "My Class"
 
    def __init__(self, object_name):
        self.object_name = object_name
 
    def set_object_name(self, object_name):
        self.object_name = object_name
 
    def set_class_name_for_object(self, class_name):
        self.class_name = class_name
 
    def set_class_name_for_class(self, class_name):
        self.__class__.class_name = class_name
 
    def get_names(self):
        return f"class_name = {self.class_name}, object_name = {self.object_name}"
 
 
a = MyClass("Object A")
b = MyClass("Object B")
print(a.get_names())
print(b.get_names())
 
# alter `object_name` of object `a` ONLY
a.set_object_name("Object AAA")
print(a.get_names())
print(b.get_names())
 
# alter `class_name` of object `a` ONLY
a.set_class_name_for_object("My Class A")
print(a.get_names())
print(b.get_names())
 
# alter `class_name` of all objects
a.set_class_name_for_class("My Class A")
print(a.get_names())
print(b.get_names())

Which returns the following:

class_name = My Class, object_name = Object A
class_name = My Class, object_name = Object B
 
class_name = My Class, object_name = Object AAA
class_name = My Class, object_name = Object B
 
class_name = My Class A, object_name = Object AAA
class_name = My Class, object_name = Object B
 
class_name = My Class A, object_name = Object AAA
class_name = My Class A, object_name = Object B

Alter State with Class Methods

A class method receives the caller class and may alter class state.

  • To alter class state, the class method makes use of the cls parameter and calls on the class attribute

For example:

class MyClass:
    class_name = "My Class"
 
    def __init__(self, object_name):
        self.object_name = object_name
 
    @classmethod
    def set_class_name(cls, class_name):
        cls.class_name = class_name
 
    def get_names(self):
        return f"class_name = {self.class_name}, object_name = {self.object_name}"
 
 
a = MyClass("Object A")
b = MyClass("Object B")
print(a.get_names())
print(b.get_names())
 
# alter `class_name` of all objects
a.set_class_name("My Class A")
print(a.get_names())
print(b.get_names())

Which returns the following:

class_name = My Class, object_name = Object A
class_name = My Class, object_name = Object B
 
class_name = My Class A, object_name = Object A
class_name = My Class A, object_name = Object B