All three are defined in a class, but they receive different implicit arguments.
| Kind | Decorator | First arg | Typical use | | --- | --- | --- | --- | | Instance method | (none) | self (instance) | Read/write instance state | | Class method | @classmethod | cls (class) | Alternative constructors, class-wide config | | Static method | @staticmethod | none | Namespaced utility related to the class |
class Job:
default_queue = "default"
def __init__(self, name, queue=None):
self.name = name
self.queue = queue or self.default_queue
def summary(self): # instance
return f"{self.name}@{self.queue}"
@classmethod
def from_dict(cls, data): # class
return cls(data["name"], data.get("queue"))
@staticmethod
def valid_name(name: str) -> bool: # static
return bool(name and name.strip())
job = Job.from_dict({"name": "etl"})
print(job.summary())
print(Job.valid_name("etl"))Rule of thumb: Need instance data → instance method. Need to construct/customize by class → classmethod. No self/cls needed but it still belongs with the class → staticmethod (or a module-level function).