Edge Python
Esc

Go to

Commands

Sign In

Sign in to publish packages and pin them by sha256.


By continuing, you accept our Terms and Conditions.

@
Palette

Classes

Classes are state containers and namespaces, not the primary abstraction. This is a design choice. Two patterns:

  • State machines: a few methods that mutate the receiver.
  • Namespaces: a bundle of related functions and constants.

Supported:

  • Single and multiple inheritance (C3 MRO) with super().
  • @property / @x.setter.
  • @staticmethod and @classmethod.
  • A curated dunder protocol for operators, indexing, iteration, hashing, context managers, and attribute fallback (see Operator overloading and protocols).

Out of scope: descriptors, metaclasses, __slots__.

State-machine pattern

3
Output

Namespace pattern

A class with no __init__ and no per-instance state is a namespace. Methods called on the class are unbound, with no self prepended.

0
3.14159
25
27
Output

Inheritance and super()

Single or multiple bases (class Sub(Base):, class C(A, B):). Methods not on the subclass resolve along the C3 linearization (the MRO). An inconsistent hierarchy raises TypeError at class creation. isinstance(x, Base) walks the ancestor chain, so Sub instances are also instances of every ancestor.

super() (zero-arg) delegates to the next class up the chain, bound to the current self. Most common in __init__ to extend a base constructor.

Rex (lab)
True
Output
B
inconsistent hierarchy
Output

Attribute access on classes vs instances

Access formResolves to
MyClass.attrclass member, returned as-is (no binding)
MyClass.method()method called directly, no self
instance.attrinstance __dict__ first, then class
instance.method()bound method, self prepended

setattr / delattr work on instances and on class objects. The latter mutates the class’s members.

Class decorators

A class decorator is called with the class object and its return value binds to the name. It can add or replace class attributes (cls.kind = ...) or return a replacement.

tagged
7
Output

Properties

@property turns a method into a read-only attribute. @x.setter makes it writable. Properties live on the class. Subclasses inherit and can override either side.

20
68.0
212.0
Output

The two-argument form property(fget, fset) also works without decorator syntax.

Static methods

@staticmethod makes a method that receives no implicit self. It is a plain function that lives in the class namespace, callable as Class.method(...) or instance.method(...) with identical arguments. Subclasses inherit it and can override it. Use it for helpers that belong to a class conceptually but need no receiver.

5
20.0
Output

The functional form staticmethod(func) also works without decorator syntax.

Class methods

@classmethod binds the class, not the instance, as the first argument. Accessed through a subclass, cls is the subclass, so alternate constructors return the right type down the hierarchy.

1 2
Color Bright
Output

The functional form classmethod(func) also works without decorator syntax.

Operator overloading and protocols

Dunders (__add__, __eq__, __getitem__, …) plug a class into language protocols. Define them in the class body. The VM calls them when the matching operator, builtin, or syntax form runs.

7
True
Output

Dunders are looked up on the class chain. The instance dict is skipped, so assigning obj.__add__ = ... has no effect. Subclasses inherit and may override.

Arithmetic

OperatorForwardReflected
a + b__add____radd__
a - b__sub____rsub__
a * b__mul____rmul__
a / b__truediv____rtruediv__
a // b__floordiv____rfloordiv__
a % b__mod____rmod__
a ** b__pow____rpow__
a @ b__matmul____rmatmul__
-a__neg__-
+a__pos__-

Return NotImplemented from the forward op to make the VM try the reflected op on the other operand. If both return NotImplemented (or neither is defined), the operation raises TypeError. An augmented assignment such as a += b first calls the in-place dunder (__iadd__, __imatmul__, …) and falls back to this pair when it is missing or returns NotImplemented.

Subclass-first ordering applies here. When type(b) is a strict subclass of type(a), b.__radd__ runs before a.__add__. This lets a subclass override an inherited reflected op without touching the base.

sub.__radd__
Output
15
10
Output

Bitwise and shifts

The bitwise and shift operators follow the same forward/reflected protocol.

OperatorForwardReflected
a | b__or____ror__
a & b__and____rand__
a ^ b__xor____rxor__
a << b__lshift____rlshift__
a >> b__rshift____rrshift__
~a__invert__-

Comparison

OperatorForwardReflected
a == b__eq____eq__
a != b__ne____ne__
a < b__lt____gt__
a <= b__le____ge__
a > b__gt____lt__
a >= b__ge____le__

!= falls back to not __eq__ (coerced to bool) when __ne__ is absent. Every other comparison returns the dunder’s raw result. A __lt__ that returns 'A.lt' yields the string, not True.

True
False
Output

Truth and length

bool(x) (and any boolean context) consults, in order:

  1. __bool__ if defined. It must return bool, else TypeError.
  2. __len__ if defined. False when the length is 0, else True.
  3. Default True.

len(x) calls __len__ directly. It must return a non-negative int.

False
False True
5
Output

Indexing and containment

FormDunderArguments
obj[i]__getitem__(self, i)
obj[i] = v__setitem__(self, i, value)
del obj[i]__delitem__(self, i)
v in obj__contains__(self, value)

Slices pass as a slice object, so obj[1:3] calls __getitem__(self, slice(1, 3, None)). Indexes on built-in sequences coerce via __index__, including slice bounds. Dict keys never coerce.

Without __contains__, v in obj falls back to iterating obj and comparing with __eq__.

1 missing
True False
Output

Iteration

MethodRole
__iter__Returns an iterator (often self).
__next__Returns the next item, or raises StopIteration to end the loop.
[1, 2, 3]
True
Output

for loops, list(x), and tuple(x) all honour the protocol.

Callable

__call__ makes instances invocable. Positional and keyword arguments are forwarded like any method call.

14
21
True
Output

Hashing

hash(x) calls __hash__. It must return an int, which is masked to INT_MAX.

Eq/hash invariant. A class that defines __eq__ without __hash__ is unhashable. hash(x) and {x: 1} raise TypeError. This prevents inconsistent dict keys. object.__hash__ is the identity hash every instance inherits, so __hash__ = object.__hash__ keeps such a class hashable.

5
found
Output

Dicts and sets place a key by its __hash__ and match it with __eq__, so an equal instance finds the entry, and the hash a key had when it went in is the one it stays under.

Representation

Function / formDunderFallback
repr(x)__repr__<ClassName instance>
str(x), print(x)__str____repr__, then default
f"{x}" (no spec)__str__same as str(x)
f"{x:spec}"__format__TypeError for a non-empty spec
f"{x!r}"__repr__-

__format__(spec) receives the spec string and must return str. int(x) on an instance calls __int__, which is also used by %d / %x / %X / %o formatting. float(x) calls __float__ and falls back to __index__. abs(x) calls __abs__.

P(3)
P(3)
P(3)
[P(3)]
Output

Attribute access fallback

__getattr__(self, name) runs only when normal lookup (instance dict, then class chain) misses. It receives the name as a string. Return the value, or raise AttributeError to surface a real miss.

1
computed:anything
computed:foo
Output

Existing attributes bypass __getattr__. Only misses trigger it.

Context managers

with cm() as x: invokes __enter__. Its return value binds to as. On exit, __exit__(exc_type, exc_value, traceback) runs. The arguments are (None, None, None) on normal exit. On a raise, they carry the exception type and value, with traceback always None. A truthy return suppresses the exception. A falsy one propagates it.

after
Output

Multiple managers (with a(), b() as x:) nest LIFO. b enters last and exits first. Each has its own implicit handler, so inner suppression still lets outer managers run their normal __exit__(None, None, None).

If __exit__ itself raises, the new exception replaces the original.

What’s not dispatched

Parsed for compatibility but never invoked on user classes:

  • __init_subclass__, __set_name__, descriptors (__get__ / __set__ / __delete__)
  • __new__. The VM constructs the instance and __init__ runs user logic.
  • Async dunders (__aenter__ / __aexit__ / __aiter__ / __anext__). async with and async for use the sync paths. See Async.

What classes do not support

  • Metaclasses, descriptors (__get__ / __set__), __slots__, ABCs, __init_subclass__.
  • Async dunders, covered above.

Reuse behaviour through free functions and composition by default. Reach for inheritance and operator overloading when the abstraction genuinely calls for them.