Loading video player…

What Makes Static Methods Different?

This lesson covers the differences between ordinary functions and @staticmethods. You’ll see a real world example of how to use @staticmethod and also learn when you’d want to use them.

00:00 You may now be wondering how are static methods and class methods any different from any other function in Python. First, let’s talk about static methods.

00:10 Static methods can be considered simple functions that take arguments and compute something and return the result. It has no information about the class or instance it’s called upon. For example, as you can see here, we have a static method defined in the class Date, which takes a datetime.

00:27 The method here simply checks to see if a particular datetime is naive or not, by simply checking the .tzinfo. If the .tzinfo is None, that means the datetime is naive and we return True, else we return False.

00:42 This is not any different from having a module-level function that does the exact same thing. Next, we define a datetime object which is naive and a datetime object which is localized.

00:58 As you can see below, d1 is a localized datetime and d2 is a naive datetime. Next, we simply create an instance of the Date object and we assign that to d. We are then able to call the .is_naive() method against that particular datetime. As you can see below, it produces False for d1 and True for d2.

01:24 This is not any different from simply calling is_naive(), which we defined above outside of the function, and passing d1

01:34 and passing d2.

01:42 These are all functionally equivalent. Sorry, this masked the first one, so just give me a second here. As you can see, these are all functionally equivalent methods.

01:55 Now, static methods are just special functions. They serve no other purpose other than for organizational purposes. For example, this .is_naive() method really fits tightly and closely knit with the Date object.

02:12 Now, it may be useful outside, but we can still simply just use the class to call the .is_naive().

02:18 Most of the time, you will never need to use static methods because you can simply define a method outside at the module level, which is easily importable.

02:28 But when doing things that are needed to be repeated, you can simply bind it with the class that you’re using and then call it like we just did down here.

Avatar image for user45755

user45755 on Sept. 29, 2021

Missing a higher level overview of intuitively what it is, why its useful, when its useful, analogies to explain…

3rd time watching still nothing

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Sept. 29, 2021

@user45755 Let’s compare the three types of methods in Python to give you a birds-eye view.

Regular methods receive a reference to a concrete object through the self parameter, which Python passes as the first argument implicitly when you call such a method. That lets you manipulate the state of a particular class instance without affecting other instances, for example:

>>> class Person:
...     def __init__(self, name):
...         self.name = name
...         self.married = False
...     def marry(self):
...         self.married = True
>>> anna, joe = Person("Anna"), Person("Joe")
>>> anna.marry()
>>> anna.married
>>> joe.married

Only Anna got married, but not Joe nor other people.

Apart from having the extra @classmethod decorator, class methods have a similar signature to standard methods. However, they receive a reference to the class rather than a concrete instance of that class. It allows for sharing state between all instances of your class, such as the number of objects created so far:

>>> class Person:
...     _num_objects = 0
...     def __init__(self, name):
...         self.name = name
...         Person._num_objects += 1
...     @classmethod
...     def get_num_objects(cls):
...         return cls._num_objects
>>> Person.get_num_objects()
>>> _ = Person("Joe"), Person("John"), Person("Anna")
>>> Person.get_num_objects()

Notice how you can call a class method without creating any instances first. This leads to a common pattern called the named constructor, which allows for creating instances of the same class in different ways:

>>> from typing import NamedTuple
>>> class Color(NamedTuple):
...     r: float
...     g: float
...     b: float
...     @classmethod
...     def monaco_blue(cls):
...         return cls(0.2, 0.5, 0.75)
...     @classmethod
...     def exotic_red(cls):
...         return cls(1, 0, 0)

>>> Color(0.25, 0.5, 0.75)
Color(r=0.25, g=0.5, b=0.75)

>>> Color.monaco_blue()
Color(r=0.2, g=0.5, b=0.75)

>>> Color.exotic_red()
Color(r=1, g=0, b=0)

You can still call the regular .__init__() method, but you can also use one of the class methods with predefined primary colors for convenience.

Finally, static methods don’t receive any implicit references at all when you call them. They work just like plain old functions, but they’re attached to a class. Sometimes it might be useful to logically group utility functions under a common namespace provided by the class:

>>> class Color(NamedTuple):
...     # ...
...     @staticmethod
...     def blend(color1, color2, alpha=0.5):
...         return color1*alpha + color2*(1-alpha)
...     def __mul__(self, scalar):
...         return Color(*[x*scalar for x in self])
...     def __add__(self, other):
...         return Color(*[sum(x) for x in zip(self, other)])
>>> Color.blend(Color.monaco_blue(), Color.exotic_red())
Color(r=0.6, g=0.25, b=0.375)

Here, the .blend() method operates on two Color instances that must be explicitly provided by the caller.

I hope this clears it up for you 👍

Become a Member to join the conversation.