A class describes a kind of thing; each object made from it holds its own data. __init__ runs when an object is created and stores the data on self, which is the object being set up:
class Invoice:
def __init__(self, number, amount):
self.number = number
self.amount = amount
Methods are functions defined in the class. Their first argument is always self; Python passes it for you, so inv.with_tax(0.08) calls with_tax(inv, 0.08). Forgetting self in the def line is the most common class error.
Values set on self belong to one object. Values written directly in the class body are shared by every object, which is a trap for lists.
__repr__ returns the text the notebook shows for an object; without it you see <__main__.Invoice object at 0x...>. @property makes a method read like an attribute, for values computed from others.
class Invoice:
def __init__(self, number, amount):
self.number = number
self.amount = amount
def with_tax(self, rate):
return round(self.amount * (1 + rate), 2)
def __repr__(self):
return f"Invoice({self.number!r}, {self.amount})"
inv = Invoice("INV-7", 100.0)
inv, inv.with_tax(0.08)
Out: (Invoice('INV-7', 100.0), 108.0). repr controls what the notebook shows.