Class methods and static methods
Methods can belong to the class too. You call such a method through the class's name, without creating an object first.
A class method has the decorator @classmethod above it, and its first parameter is cls instead of self. Where self is the object, cls is the class itself, and Python fills it in for you just as it fills in self. A static method has the decorator @staticmethod and no such parameter at all: it's an ordinary function that lives in the class because it belongs with it.
class Time:
def __init__(self, hours, minutes):
if not Time.valid(hours, minutes):
raise ValueError(f"Not a valid time: {hours}:{minutes}")
self.hours = hours
self.minutes = minutes
@staticmethod
def valid(hours, minutes):
return 0 <= hours < 24 and 0 <= minutes < 60
@classmethod
def from_text(cls, text):
parts = text.split(":")
return cls(int(parts[0]), int(parts[1]))
@classmethod
def midnight(cls):
return cls(0, 0)
def __str__(self):
return f"{self.hours:02}:{self.minutes:02}"
print(Time.valid(25, 0))
lunch = Time.from_text("12:30")
print(lunch)
print(Time.midnight())
False
12:30
00:00(In the f-string, :02 writes a number with at least two digits, padding it with a zero.)
Time.valid(25, 0)looks only at the two numbers it gets, so it needs noTimeobject to work on. Any code can ask it whether a time makes sense, and__init__asks it first thing, before it stores anything.from_textandmidnightcreate new objects:cls(...)calls the class, exactly asTime(...)would. Class methods like these are a handy way to offer more than one way to create an object.
Which one to choose
Both kinds are called the same way, Time.valid(...) or Time.from_text(...). The difference is what they get:
- an ordinary method gets the object (
self), and is called on an object; - a class method gets the class (
cls), so it can create objects withcls(...)and use class variables ascls.name; - a static method gets neither: it works with the arguments you give it. Like any other code, it can still reach the class by its name, for example to read a class variable such as
Ticket.soldbelow, but it has noselfand nocls.
A class method that works with a class variable:
class Ticket:
sold = 0
def __init__(self):
Ticket.sold += 1
@classmethod
def sales_report(cls):
return f"{cls.sold} tickets sold"
Ticket()
Ticket()
print(Ticket.sales_report())
2 tickets soldCalling an ordinary method through the class doesn't work, because there is no object to be its self. Time.__str__() would stop with TypeError: Time.__str__() missing 1 required positional argument: 'self'.