class

class builds a new type. Attributes set on self belong to one instance; attributes written in the class body are shared by all of them.

DefinitionsPython 3 (all)Live demo
class
class Name:
    attr = value
    def method(self):
        ...
with __init__
class Name:
    def __init__(self, x):
        self.x = x
inheritance
class Child(Parent):
    def __init__(self, x):
        super().__init__(x)
dataclass
@dataclass
class Point:
    x: int
    y: int = 0
Use for
bundling data with the functions that work on it; your own types
Result
binds Name to a new class object; calling Name(...) makes instances
Pairs with
__init__, self, super(), @dataclass, @property, isinstance()
Watch out
a mutable class attribute (items = []) is shared by every instance

Demo

Live evaluation
Add items to cart a only. The list created in __init__ belongs to a; the list in the class body is shared with b.
Try:
Inputs
itemslistcomma-separated
Code
class Cart:
    shared = []

    def __init__(self):
        self.own = []

    def add(self, item):
        self.shared.append(item)
        self.own.append(item)

a, b = Cart(), Cart()
for item in ['apple', 'pear']:
    a.add(item)
(a.own, b.own, b.shared)
Result
(['apple', 'pear'], [], ['apple', 'pear'])

In the class vs instance tab, b never called add(), yet b.shared holds every item: shared lives on the class, so a.shared and b.shared are the same list. In the attribute lookup tab, sound is found on Dog before Animal is even checked (overriding), legs falls through to Animal, and __init__ comes all the way from object. The trace is a simplified model of what rex.attr does: real lookup also gives data descriptors such as properties on the class priority over the instance dict.

Syntax slots

NameTypeRequiredDescription
NamenameyesThe name the new class is bound to. By convention CapWords.
Baseexpression listnoClasses to inherit from, comma-separated. Omitted means object. Keyword arguments such as metaclass=... also go here.
bodyblockyesRuns once, when the class statement executes. Names it assigns (attributes, def methods) become the class namespace.
selfparameteryesFirst parameter of every normal method: the instance the method was called on. The name self is a convention, not a keyword.

Common patterns

Alternative constructor
A classmethod receives the class, so subclasses get instances of themselves.
class Temp:
    def __init__(self, celsius):
        self.celsius = celsius

    @classmethod
    def from_fahrenheit(cls, f):
        return cls((f - 32) * 5 / 9)
Computed attribute
@property makes a method read like an attribute.
class Rect:
    def __init__(self, w, h):
        self.w, self.h = w, h

    @property
    def area(self):
        return self.w * self.h
Dataclass with a mutable default
field(default_factory=list) gives each instance its own list.
from dataclasses import dataclass, field

@dataclass
class Order:
    id: int
    items: list = field(default_factory=list)
Readable repr
Define __repr__ so instances print as something useful instead of <... object at 0x...>.
class Money:
    def __init__(self, cents):
        self.cents = cents

    def __repr__(self):
        return f'Money({self.cents!r})'

Examples

1. __init__ and a method
class Dog: def __init__(self, name): self.name = name def speak(self): return f'{self.name} says woof' Dog('Rex').speak()
Returns
'Rex says woof'
2. A class attribute is shared
class Counter: created = 0 def __init__(self): Counter.created += 1 Counter() Counter() Counter.created
Returns
2
3. Inheritance with super()
class Animal: def __init__(self, name): self.name = name class Cat(Animal): def __init__(self, name, indoor): super().__init__(name) self.indoor = indoor vars(Cat('Tom', True))
Returns
{'name': 'Tom', 'indoor': True}
4. Method resolution order
class A: pass class B(A): pass class C(B): pass [k.__name__ for k in C.__mro__]
Returns
['C', 'B', 'A', 'object']
5. A custom __repr__
class Money: def __init__(self, cents): self.cents = cents def __repr__(self): return f'Money({self.cents})' [Money(5), Money(250)]
Returns
[Money(5), Money(250)]
6. dataclass writes __init__, __repr__, __eq__
from dataclasses import dataclass @dataclass class Point: x: int y: int = 0 (Point(3), Point(1, 2) == Point(1, 2))
Returns
(Point(x=3, y=0), True)
7. A class is an object too
class Empty: pass (type(Empty), Empty.__name__, isinstance(Empty(), Empty))
Returns
(<class 'type'>, 'Empty', True)

Pitfalls

1. A mutable class attribute shared by every instance
members = [] in the class body creates ONE list stored on the class. Every instance that appends to self.members appends to that same list.
list in the class body
class Team:
    members = []

    def join(self, name):
        self.members.append(name)

a, b = Team(), Team()
a.join('Ann')
b.members
['Ann']
create it in __init__
class Team:
    def __init__(self):
        self.members = []

    def join(self, name):
        self.members.append(name)

a, b = Team(), Team()
a.join('Ann')
b.members
[]
2. Forgetting self
The instance is passed as the first argument automatically. A method defined without a parameter for it fails when called on an instance.
no self parameter
class Greeter:
    def hello():
        return 'hi'

Greeter().hello()
TypeError: Greeter.hello() takes 0 positional arguments but 1 was given
take self
class Greeter:
    def hello(self):
        return 'hi'

Greeter().hello()
'hi'
3. self.count += 1 does not update the class attribute
Reading self.count finds the class value, but assigning to self.count creates an instance attribute that shadows it. The class attribute never changes.
augmented assign on self
class Counter:
    count = 0

    def __init__(self):
        self.count += 1

Counter()
Counter()
Counter.count
0
assign on the class
class Counter:
    count = 0

    def __init__(self):
        type(self).count += 1

Counter()
Counter()
Counter.count
2
4. Overriding __init__ without calling super().__init__()
A subclass __init__ replaces the parent one completely, so the parent never sets its attributes.
parent init skipped
class Animal:
    def __init__(self, name):
        self.name = name

class Dog(Animal):
    def __init__(self, name):
        self.tricks = []

Dog('Rex').name
AttributeError: 'Dog' object has no attribute 'name'
call super().__init__
class Animal:
    def __init__(self, name):
        self.name = name

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)
        self.tricks = []

Dog('Rex').name
'Rex'

When to use

Use it
  • Data and the operations on it belong together (a Cart with add() and total())
  • You need several objects with the same shape and behaviour
  • You want your own type to work with len(), ==, for, with and friends (dunder methods)
Reach for something else
  • Just a record of fields → @dataclass (still a class, far less code) or a NamedTuple
  • A class with one method and __init__ → usually a plain function
  • A bag of constants or stateless helpers → a module

Notes

CPython impl
The body runs like a function body; its local namespace becomes the class __dict__, with __module__ and __doc__ added (and, since 3.13, __firstlineno__ and __static_attributes__)
Scope
Names defined in the class body are NOT visible inside methods as bare names — use self.name or ClassName.name
self
self is only a convention; Python passes the instance as the first positional argument whatever it is called
Generics
Since 3.12 a class can declare type parameters directly: class Box[T]: ...

FAQ

The instance the method was called on. obj.method(1) is effectively Class.method(obj, 1), so the first parameter receives obj. It is named self by convention only — any name works, but every normal method needs that first parameter.

History

3.9
Classes may be decorated with any valid assignment_expression (PEP 614).
3.12
Type parameter lists (class Box[T]: ...) are new.