The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Define a class | class Account: pass | View examples |
| Initialize instance state | def __init__(self, owner): self.owner = owner | View examples |
| Define instance behavior | def deposit(self, amount): self.balance += amount | View examples |
| Define shared state | class Account: currency = 'USD' | View examples |
| Add an alternate constructor | @classmethod | View examples |
| Attach a utility | @staticmethod | View examples |
| Expose computed state | @property | View examples |
| Create a subclass | class Admin(User): pass | View examples |
| Delegate through the MRO | super().__init__(name) | View examples |
| Test compatible type | isinstance(user, User) | View examples |
| Generate record methods | @dataclass | View examples |
| Create a fresh mutable default | tags: list[str] = field(default_factory=list) | View examples |
| Emulate immutability | @dataclass(frozen=True) | View examples |
| Generate slots | @dataclass(slots=True) | View examples |
| Convert fields recursively | payload = asdict(order) | View examples |
| Copy with changes | updated = replace(item, price=12) | View examples |
Classes combine state with behavior and define a new object type. Keep instance state on self, use class state only when it is genuinely shared, and favor small composable objects over deep inheritance. Dataclasses remove record-like boilerplate but do not replace validation or domain design.
Step by step
Detailed examples
Put per-object state on the instance
Creating a class executes its body once and produces a class object. Calling the class creates an instance and invokes __init__ to initialize it. Instance methods are functions retrieved through the instance, which binds that instance as self; self is a convention, but using it consistently makes code readable.
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError('amount must be positive')
self.balance += amount
return self.balance
account = Account('Ada', 10)
print(account.deposit(5))
print(account.owner) 15
AdaSeparate shared defaults from mutable instance state
Attribute lookup checks the instance and then its class hierarchy. Assigning through an instance normally creates or replaces an instance attribute, leaving the class attribute unchanged. Never put a mutable list or dictionary on the class merely as an instance default, because every instance would share it.
class Report:
format = 'text'
first = Report()
second = Report()
first.format = 'html'
print(first.format)
print(second.format)
print(Report.format) html
text
textOffer meaningful construction and access APIs
A classmethod is well suited to alternate constructors because cls preserves subclassing. A staticmethod is appropriate only when the operation belongs in the class namespace but needs no object state. A property can preserve attribute-style access for computed or validated values; avoid hiding expensive or surprising work behind it.
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
@classmethod
def from_full_name(cls, text):
first, last = text.split(maxsplit=1)
return cls(first, last)
@property
def full_name(self):
return f'{self.first} {self.last}'
person = Person.from_full_name('Grace Hopper')
print(person.full_name) Grace HopperUse inheritance for genuine substitutability
A subclass should satisfy the expectations of code written for its base class. super() follows the method-resolution order, which matters especially with multiple inheritance. Prefer composition when one object merely uses another service; it keeps dependencies explicit and avoids exposing every base-class behavior.
class User:
def __init__(self, name):
self.name = name
def label(self):
return self.name
class Admin(User):
def __init__(self, name, scope):
super().__init__(name)
self.scope = scope
admin = Admin('Lin', 'billing')
print(admin.label())
print(isinstance(admin, User)) Lin
TrueGenerate boilerplate for record-like classes
@dataclass examines annotated fields and generates an initializer, representation, and equality by default. Type annotations are not enforced at runtime. Field order affects the initializer and comparisons, so treat it as part of the API and put required fields before fields with defaults.
from dataclasses import dataclass
@dataclass
class LineItem:
sku: str
quantity: int
unit_price: float
def total(self):
return self.quantity * self.unit_price
item = LineItem('A-42', 3, 2.5)
print(item)
print(item.total()) LineItem(sku='A-42', quantity=3, unit_price=2.5)
7.5Make defaults safe and object guarantees explicit
Use default_factory for mutable defaults so every instance receives a fresh object. frozen=True emulates read-only fields but cannot make referenced mutable objects immutable. slots=True can reduce per-instance storage and prevent arbitrary new attributes; it returns a new slotted class, so review inheritance interactions.
from dataclasses import dataclass, field
@dataclass
class Note:
text: str
tags: list[str] = field(default_factory=list)
@dataclass(frozen=True, slots=True)
class Coordinate:
x: int
y: int
first = Note('One')
second = Note('Two')
first.tags.append('urgent')
print(first.tags, second.tags)
print(Coordinate(3, 4)) ['urgent'] []
Coordinate(x=3, y=4)Copy and serialize dataclass values deliberately
replace constructs a new object through the generated initializer, making it useful for frozen records and controlled updates. asdict recursively converts nested dataclasses and containers and deep-copies other objects, which can be more work than a shallow projection. Neither function is a general validation or wire-format layer.
from dataclasses import asdict, dataclass, replace
@dataclass(frozen=True)
class Product:
sku: str
price: int
original = Product('A-42', 10)
updated = replace(original, price=12)
print(original.price, updated.price)
print(asdict(updated)) 10 12
{'sku': 'A-42', 'price': 12}Local code tester
Model a record with behavior
Edit a dataclass, add validation or derived behavior, and create updated immutable copies.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



