Home Python @staticmethod vs @classmethod
Post
Cancel

Python @staticmethod vs @classmethod

Python Functions are First-class Objects

In Python functions are first-class objects which means that functions can be assigned to variables or passed as an argument for another function in the same manner as primitive data types and objects. For example, in the following code, the function operator has three parameters operation, x, and y. While x and y can be primitive data types, operation must be a function. Inside of operator the arguments x and y are passed to operation, whose result is then returned:

1
2
3
4
5
6
7
8
9
10
11
12
def operator(operation, x, y):
    return operation(x, y)

def add(x, y):
    return x+y

def sub(x, y):
    return x-y

if __name__ == "__main__":
    print(operator(add, 23, 42))
    print(operator(sub, 23, 42))

Output

1
2
65
-19

In the __main__ (check out this article over here if you want to know why you should always use __name__ == "__main__") the functions add and sub are passed as operation to operator and those two carry out addition or subtraction when called inside of operator. This concept of passing functions as arguments to other functions is also called higher-order functions which allows us to embed Python functions into other functions.

What is a Decorator in Python

The first-class nature of Python functions gives us the ability to encapsulate a function inside another function:

1
2
3
4
5
6
7
8
9
10
11
12
def succ(function):
    def wrapper(*args):
        result = function(*args)
        return result+1
    return wrapper

def add(x, y):
    return x+y

if __name__ == "__main__":
    add_plus_one = succ(add)
    print(add_plus_one(23, 42))

Output

1
66

In the code above, the succ function takes a function as an argument and then calls that function and adds one to the result, hence the name succ meaning successor function. In the __main__ section, add is passed to succ to construct a new function add_plus_one, which adds two numbers and adds an additional one to the addition.

Instead of passing a function to a function to get a new function, we can use decorators as a shortcut:

1
2
3
4
5
6
7
8
9
10
11
12
def succ(function):
    def wrapper(*args):
        result = function(*args)
        return result+1
    return wrapper

@succ
def add(x, y):
    return x+y

if __name__ == "__main__":
    print(add(23, 42))

Output

1
66

The statement @succ above add does exactly the same thing as succ(add) but a lot cleaner and globally.

Python @staticmethod

When you have a class and want a method from that class without instantiating an object, you are looking for a static method. In Java or C++ one would declare a function as static with the static keyword. In Python however, we use the decorator @staticmethod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Accumulator:
    def __init__(self):
        self.acc = 0

    def add(self, x):
        self.acc += x

    @staticmethod
    def sub(x,y):
        return x-y

if __name__ == "__main__":
    a = Accumulator()
    a.add(23)
    a.add(42)

    print(a.acc)

    print(Accumulator.sub(23, 42))

Output

1
2
65
-19

In the class Accumulator above, a value passed to add is added to the variable self.acc, which is only instantiated when an object of Accumulator is created. However, our class might have useful methods that don’t depend on object attributes, such as the sub method, which only subtracts two numbers from each other that are passed as arguments and therefore does not access data in self. To make sub usable without instantiating an object of Accumulator sub is decorated with @staticmethod and is missing the parameter self. In the __main__ section, we see that sub is called, putting the class name in front of it.

A Python static method knows nothing about the class it is part of and works only with its parameters.

Python @classmethod

Python classes can have attributes and methods such as objects. A class attribute can be helpful if all objects share a common value, while class methods allow us to manipulate class attributes. For example, it might be helpful to track how many instances of a class have been created:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Accumulator:
    count = 0

    def __init__(self):
        Accumulator.increase_count()
        self.acc = 0

    def add(self, x):
        self.acc += x

    @classmethod
    def increase_count(cls):
        cls.count += 1

    @classmethod
    def get_count(cls):
        return cls.count

if __name__ == "__main__":
    a = Accumulator()
    print(Accumulator.get_count())

    b = Accumulator()
    print(Accumulator.get_count())

Output

1
2
1
2

The code above Accumulator has the class attribute count and the class methods increase_count and get_count, which are both decorated with @classmethod. Every time a new Accumulator object is created, __init__ calls Accumulator.increase_count, which adds one to count and thereby tracks how many Accumulator objects have been instantiated. Looking closely at the class methods, we can see they have the cls parameter, representing the Accumulator class, and there is no self parameter. Under __main__, we can see that every time a new object is created, the count is increased by one, which is an attribute of the class and not the individual objects.

A Python class method can access and manipulate the attributes of a class and its first parameter is always the class itself.

Conclusion

This article looked at the difference between a static and a class method in Python. While static methods know nothing about the class, class methods can access and manipulate class attributes. The decorators @staticmethod and @classmethod are used to declare a static or class method in Python and allow you to use functions of a class without instantiating an object of that class.

This post is licensed under CC BY 4.0 by the author.