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:
class Invoice:
RATE = 0.20
@staticmethod
def number_is_valid(number):
return len(number) == 8 and number.isdigit()
Invoice.number_is_valid("20260819") # TrueThe 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.
| Spelling | First parameter received | Pick it when |
|---|---|---|
| Instance method | self, the object | The work depends on the object's data |
classmethod | cls, the class | The work depends on the class, not the object |
@staticmethod | Nothing at all | The 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__.
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.
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.
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 givenThe 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.
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 expectedBook.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
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.
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.
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.