staticmethod in Python: the function filed inside a class

staticmethod files a plain function inside a class, with no self and no cls. When that filing earns its place, and the forgotten-decorator trap.
5 min read
Believemy logo

Definition

A function written inside a class usually receives the object it works on, through self. But some functions need none of that: they transform their arguments, without ever asking anything of the object or the class. Giving them a parameter they never use would be pointless, and that is exactly what @staticmethod lets you avoid.

@staticmethod is a decorator that files a plain function inside a class, with neither self nor cls. Here is what that looks like on a validation function:

PYTHON
class Invoice:
    RATE = 0.20

    @staticmethod
    def number_is_valid(number):
        return len(number) == 8 and number.isdigit()

Invoice.number_is_valid("20260819")   # True

The call works just as well on the class as on an instance: since the function receives nothing behind the scenes, it always gets exactly the same arguments, no matter which one you call it through.


The three kinds of methods

Python offers three ways of writing a method. The choice between them comes down to one question: what does this method need in order to do its job?

The table below lays out the three answers, and what each receives automatically as its first argument.

SpellingFirst parameter receivedPick it when
Instance methodself, the objectThe work depends on the object's data
classmethodcls, the classThe work depends on the class, not the object
@staticmethodNothing at allThe work depends only on the arguments given

The static method is the only one of the three whose signature hides nothing: what you write between the brackets is exactly what it receives. You can therefore test it in isolation, without building an object or preparing any __init__.

Good to know

The difference shows up a little on the performance side too: an instance method builds a small intermediate object on every call, the bound method, which a static method skips entirely.


When it earns its place

Filing a function inside a class is never mandatory. The question worth asking: why not write it alongside, as an independent function? The good case is a utility function that belongs to the vocabulary of the class without touching its state: a format check, a unit conversion, a calculation nothing else uses. Filing it inside the class puts it where the next reader will look for it, rather than in the module, among twenty unrelated functions.

The class below shows two methods sharing it without getting in each other's way.

PYTHON
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius

    @staticmethod
    def fahrenheit_to_celsius(value):
        return (value - 32) * 5 / 9

    @classmethod
    def from_fahrenheit(cls, value):
        return cls(cls.fahrenheit_to_celsius(value))

The conversion depends on no object: it is a formula, so it stays static. The alternative constructor needs the class instead, to build the instance, so it takes cls. The two live together well: each receives exactly what it needs.


The forgotten decorator trap

This is the most frequent mistake on the subject, and it fires late, once the code is already written. Without the at sign, Python treats the function as an ordinary instance method and slips the object in as the first argument on every call.

The consequence then depends on how the method gets called.

PYTHON
class Invoice:
    def number_is_valid(number):     # decorator forgotten
        return len(number) == 8

Invoice.number_is_valid("20260819")   # goes through
invoice = Invoice()
invoice.number_is_valid("20260819")

# TypeError: number_is_valid() takes 1 positional argument but 2 were given

The call made from the class goes through without complaint, no object ever joining the arguments. It is the call made from an instance that fails, with a TypeError announcing one argument too many that appears nowhere in your own code: it is the instance, handed over in silence. That gap of exactly one argument between what the method declares and what it receives is the most reliable signature of a missing decorator.


Static methods and inheritance

A static method is inherited like anything else, and a child class may replace it. But it never receives self or cls: if its code names a class outright, that class stays the same one, no matter which child class the call was made through.

PYTHON
class Product:
    RATE = 0.20

    @staticmethod
    def with_tax(amount):
        return amount * (1 + Product.RATE)   # frozen on Product

class Book(Product):
    RATE = 0.055

Book.with_tax(100)   # 120.0, where 105.5 was expected

Book.with_tax(100) returns 120.0 rather than the 105.5 expected: the method has no idea Book exists, it only knows Product, spelled out in its body. As soon as a class attribute enters the calculation, the method is no longer static by nature: a classmethod should be written instead, so that cls points to the right class. Useful tell: if a static method's body names its own class, be suspicious.


Frequently asked questions

Question

Why not write a plain function outside the class?

Nothing forbids it, and it is often the better choice: a class cluttered with unrelated functions quickly becomes tiresome to read. The criterion is the vocabulary of the domain being modelled. If the function only makes sense in relation to the class, like validating an invoice number, filing it inside the class makes that link explicit. If it serves elsewhere, it belongs to the module. A static method nobody ever calls through its class name has probably ended up in the wrong place.

Question

What exactly is the difference with classmethod?

A class method receives the class as its first argument, a static method receives nothing. The consequence: the first follows the class actually called, even from a child class, the second stays frozen on whatever its code names, as with Book and Product. As soon as a child class needs to change the result, the static version turns into a silent trap.

Question

Can it be called from inside the class body?

Since Python 3.10, yes: the object produced by the decorator became directly callable, which was not the case before. On earlier versions, the same spelling raises a puzzling message, 'staticmethod' object is not callable, and forces a detour through .__func__ to get the original function back.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.