A class is an object that makes other objects. A class statement runs its
body as a block and creates the class from the names the body binds (Language Reference
8.8). The special methods that a class can define are on
Data model.
The class statement
classdef: [decorators] "class" classname [type_params] [inheritance] ":" suite
inheritance: "(" [argument_list] ")"
class Account:
"""A bank account."""
interest = 0.02 # class attribute
def __init__(self, owner):
self.owner = owner # instance attribute
self.balance = 0
def deposit(self, amount):
self.balance += amount
account = Account("Ada")
account.deposit(10)
- The body runs when the statement is reached, in a new namespace. The names it binds become the class's attributes, and the class is then bound to its name.
- A class with no base inherits from
object. - Calling the class runs
__new__, then__init__. - Keyword arguments in the base list, other than
metaclass, are passed to__init_subclass__. - Square brackets after the name make a generic class (Python 3.12).
- A class can be decorated like a
function:
@decoratorbeforeclass.
Names bound in a class body are not visible inside its methods.
Attributes and methods
Reading x.a looks in the instance's __dict__, then in the
class and its bases. A class attribute is shared by all instances until one instance
assigns its own, which hides it for that instance only. A mutable class attribute
is shared in full, so set up per-instance data in __init__.
| Kind of method | Declared | First argument |
|---|---|---|
| Instance method | def m(self, ...) | The instance, passed automatically |
| Class method | @classmethod | The class |
| Static method | @staticmethod | None passed |
A function stored in a class is turned into a bound method by the
descriptor protocol. x.m makes a method object
whose __self__ is x and whose __func__ is the
function, so x.m() calls type(x).m(x). self is
only a convention.
Private names
Python has no access control, and a leading underscore marks a name as internal
by convention. A name written as __x inside a class, not ending in two
underscores, is rewritten to _ClassName__x (6.2.2.1). This avoids
clashes with names in subclasses. It does not hide anything.
class C:
__secret = 1
def read(self):
return self.__secret # means self._C__secret
C().read() # 1
C._C__secret # 1
hasattr(C, "__secret") # False
getattr are not changedClass attributes
| Attribute | Meaning |
|---|---|
__name__, __qualname__ | The name, and the dotted path to it |
__module__ | The defining module |
__doc__ | The docstring |
__dict__ | A read-only view of the namespace |
__bases__ | The direct bases, as a tuple |
__mro__ | The method resolution order |
__annotations__, __annotate__ | The class's annotations |
__type_params__ | Its type parameters (3.12) |
__firstlineno__ | The line number of the definition (3.13) |
__static_attributes__ | The names assigned through self.X in its methods (3.13) |
Inheritance
A class names its bases in the list after its name, and it inherits their attributes.
A method with the same name overrides the base's. isinstance and
issubclass test the relation. Base classes that disallow subclassing,
such as bool, raise TypeError.
Multiple inheritance and the MRO
The method resolution order is the sequence of classes searched for an
attribute. Python computes it with the C3 algorithm (8.8.1). A class always comes
before its bases, and the bases keep the order in which they are listed. If no
consistent order exists, creating the class raises TypeError.
class A:
def f(self): return "A"
class B(A):
def f(self): return "B" + super().f()
class C(A):
def f(self): return "C" + super().f()
class D(B, C):
def f(self): return "D" + super().f()
D().f() # 'DBCA'
[k.__name__ for k in D.__mro__] # ['D', 'B', 'C', 'A', 'object']
super
super() with no arguments, inside a method, returns a proxy that
continues the search in the MRO after the current class, using the object's own MRO.
So it does not simply mean the parent: in the example, super() inside
B.f finds C.f when the object is a D. The
no-argument form relies on a hidden __class__ cell that the compiler
creates.
Abstract classes
The abc module lets a class declare methods that subclasses must
implement. Instantiating a class with an abstract method left unimplemented raises
TypeError. typing.Protocol offers
structural typing instead.
Descriptors
A descriptor is an object stored in a class whose type defines one or more of these methods (3.3.2.2). Attribute access on instances then goes through them.
| Method | Called by |
|---|---|
__get__(self, instance, owner=None) | Reading the attribute |
__set__(self, instance, value) | Assigning to it |
__delete__(self, instance) | Deleting it |
__set_name__(self, owner, name) | When the owning class is created (3.6, PEP 487) |
A data descriptor defines __set__ or __delete__. A
non-data descriptor defines only __get__. Attribute lookup on an
instance uses this order:
- A data descriptor on the class.
- The instance's
__dict__. - A non-data descriptor or a plain attribute on the class.
__getattr__, if the class defines it. OtherwiseAttributeError.
Functions are non-data descriptors, which is why an instance attribute can hide a
method. property, classmethod and
staticmethod are descriptors too.
class Doubled:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner=None):
if instance is None:
return self
return instance.__dict__[self.name] * 2
def __set__(self, instance, value):
instance.__dict__[self.name] = value
class Thing:
size = Doubled()
t = Thing()
t.size = 4
t.size # 8
Properties
property is a built-in descriptor that makes method calls look like
attribute access. Assigning to a property with no setter raises
AttributeError.
class Temperature:
def __init__(self):
self._celsius = 0.0
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("too cold")
self._celsius = value
__slots__
A class that sets __slots__ to a sequence of names gets a fixed layout
instead of a __dict__ for each instance, which saves memory and rejects
any other attribute (3.3.2.4). The class needs __dict__ or
__weakref__ listed in its slots to have them. Slots in a base are
inherited, but two bases with non-empty slots usually cannot be combined.
Class creation and metaclasses
A class's type is its metaclass, normally type. Calling
type(name, bases, namespace) makes a class directly. A class chooses another
metaclass with class C(metaclass=M): (PEP 3115). The steps to create a
class are (3.3.3):
- Any base objects that are not types are resolved through
__mro_entries__. - The most derived metaclass among the bases and the
metaclassargument is chosen. Conflicting metaclasses raiseTypeError. - The namespace comes from the metaclass's
__prepare__, or is an empty dictionary. - The class body runs in that namespace.
- The class is created by calling
metaclass(name, bases, namespace), which runs__new__and__init__. - Each attribute's
__set_name__runs, and then the parent's__init_subclass__. - Class decorators are applied, and the class is bound to its name.
class Meta(type):
def __new__(mcs, name, bases, namespace, **kwargs):
cls = super().__new__(mcs, name, bases, namespace)
cls.created_by = "Meta"
return cls
class Model(metaclass=Meta):
pass
Model.created_by # 'Meta'
type(Model) # <class '__main__.Meta'>
__init_subclass__
Many uses of metaclasses can use __init_subclass__ instead, a hook on a
base class that runs when a subclass is created (PEP 487, Python 3.6):
class Plugin:
registry = []
def __init_subclass__(cls, tag=None, **kwargs):
super().__init_subclass__(**kwargs)
cls.tag = tag
Plugin.registry.append(cls)
class Upload(Plugin, tag="up"):
pass
Upload.tag # 'up'
Dataclasses
The dataclasses module (PEP 557, Python 3.7) generates methods from
annotated class attributes, so that a class of plain fields needs no
boilerplate.
from dataclasses import dataclass, field, KW_ONLY, InitVar
@dataclass(order=True, frozen=True)
class Point:
x: int
y: int = 0
@dataclass
class Order:
items: list[str] = field(default_factory=list)
tax: InitVar[int] = 0
_: KW_ONLY
tag: str = ""
def __post_init__(self, tax):
self.total_tax = tax
Point(1) # Point(x=1, y=0)
Point(1) < Point(2) # True
| Parameter | Default | Effect |
|---|---|---|
init, repr, eq | True | Generate __init__, __repr__, __eq__ |
order | False | Generate __lt__ and the other orderings. Needs eq |
unsafe_hash | False | Force a __hash__ |
frozen | False | Assigning a field raises FrozenInstanceError |
match_args | True | Generate __match_args__ (3.10) |
kw_only | False | Make all fields keyword-only (3.10) |
slots | False | Generate __slots__ and return a new class (3.10) |
weakref_slot | False | Add a __weakref__ slot; needs slots (3.11) |
- A field is any annotated class attribute.
ClassVarfields are left out, andInitVarfields are passed only to__post_init__. - A mutable default such as
[]is aValueError. Usefield(default_factory=list). - With
eq=Trueandfrozen=False,__hash__is set toNone, so instances are unhashable. Witheq=Trueandfrozen=True, a hash is generated. __post_init__runs at the end of the generated__init__. The generated__init__does not call a base's__init__.- After
_: KW_ONLY, the following fields are keyword-only. dataclasses.replace,asdict,astupleandfieldswork on instances.