You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/pages/language/dunders.md
+36-36Lines changed: 36 additions & 36 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,12 +7,12 @@ Dunders (`__add__`, `__eq__`, `__getitem__`, ...) plug a class into language pro
7
7
8
8
```python
9
9
classV:
10
-
def__init__(self, n):
11
-
self.n = n
12
-
def__add__(self, o):
13
-
return V(self.n + o.n)
14
-
def__eq__(self, o):
15
-
returnself.n == o.n
10
+
def__init__(self, n):
11
+
self.n = n
12
+
def__add__(self, o):
13
+
return V(self.n + o.n)
14
+
def__eq__(self, o):
15
+
returnself.n == o.n
16
16
17
17
print((V(3) + V(4)).n)
18
18
print(V(3) == V(3))
@@ -23,7 +23,7 @@ print(V(3) == V(3))
23
23
True
24
24
```
25
25
26
-
Dunders are looked up on the class chain (instance dict skipped). Subclasses inherit and may override, operator overloading composes with [single-level inheritance](/language/classes#inheritance-and-super). Monomorphic sites (same class for both operands) promote through the IC after 4 hits and bypass lookup entirely.
26
+
Dunders are looked up on the class chain (instance dict skipped). Subclasses inherit and may override; operator overloading composes with [single-level inheritance](/language/classes#inheritance-and-super). Monomorphic sites (same class for both operands) promote through the IC after 4 hits and bypass lookup entirely.
27
27
28
28
## Arithmetic
29
29
@@ -36,19 +36,19 @@ Dunders are looked up on the class chain (instance dict skipped). Subclasses inh
36
36
|`a // b`|`__floordiv__`|`__rfloordiv__`|
37
37
|`a % b`|`__mod__`|`__rmod__`|
38
38
|`a ** b`|`__pow__`|`__rpow__`|
39
-
|`-a`|`__neg__`|,|
39
+
|`-a`|`__neg__`| —|
40
40
41
41
Returning `NotImplemented` from the forward op tells the VM to try the reflected op on the other operand. Both `NotImplemented` (or neither defined) -> `TypeError`.
42
42
43
-
Subclass-first: when `type(b)` is a strict subclass of `type(a)`, `b.__radd__` runs before `a.__add__`, lets a subclass override an inherited reflected op without touching the base.
43
+
Subclass-first: when `type(b)` is a strict subclass of `type(a)`, `b.__radd__` runs before `a.__add__` — letting a subclass override an inherited reflected op without touching the base.
`!=` falls back to `not __eq__` when `__ne__` is absent. Results coerce to `bool`,`__lt__` returning `'A.lt'` yields `True`, not the string.
73
+
`!=` falls back to `not __eq__` when `__ne__` is absent. Results coerce to `bool` —`__lt__` returning `'A.lt'` yields `True`, not the string.
74
74
75
75
## Truth and length
76
76
@@ -84,13 +84,13 @@ print((3 + Money(7)).n)
84
84
85
85
```python
86
86
classEmpty:
87
-
def__bool__(self):
88
-
returnFalse
87
+
def__bool__(self):
88
+
returnFalse
89
89
90
90
classContainer:
91
-
def__init__(self, n): self.n = n
92
-
def__len__(self):
93
-
returnself.n
91
+
def__init__(self, n): self.n = n
92
+
def__len__(self):
93
+
returnself.n
94
94
95
95
print(bool(Empty()))
96
96
print(bool(Container(0)), bool(Container(3)))
@@ -125,16 +125,16 @@ Absent `__contains__`: `v in obj` falls back to iterating `obj` with `__eq__`.
125
125
126
126
```python
127
127
classUp:
128
-
def__init__(self, stop):
129
-
self.i =0
130
-
self.stop = stop
131
-
def__iter__(self):
132
-
returnself
133
-
def__next__(self):
134
-
ifself.i >=self.stop:
135
-
raiseStopIteration
136
-
self.i +=1
137
-
returnself.i
128
+
def__init__(self, stop):
129
+
self.i =0
130
+
self.stop = stop
131
+
def__iter__(self):
132
+
returnself
133
+
def__next__(self):
134
+
ifself.i >=self.stop:
135
+
raiseStopIteration
136
+
self.i +=1
137
+
returnself.i
138
138
139
139
print(list(Up(3)))
140
140
```
@@ -151,8 +151,8 @@ print(list(Up(3)))
151
151
152
152
```python
153
153
classDouble:
154
-
def__call__(self, x):
155
-
return x *2
154
+
def__call__(self, x):
155
+
return x *2
156
156
157
157
d = Double()
158
158
print(d(7))
@@ -168,7 +168,7 @@ True
168
168
169
169
`hash(x)` calls `__hash__`; must return `int` (masked to `INT_MAX`).
170
170
171
-
Eq/hash invariant: a class defining `__eq__` without `__hash__` is unhashable,`hash(x)` and `{x: 1}` raise `TypeError`. Prevents inconsistent dict keys.
171
+
Eq/hash invariant: a class defining `__eq__` without `__hash__` is unhashable —`hash(x)` and `{x: 1}` raise `TypeError`. Prevents inconsistent dict keys.
172
172
173
173
```python
174
174
classK:
@@ -198,7 +198,7 @@ Built-in dict/set still compare instance keys by identity (`Val` bits); user `__
198
198
|`str(x)`, `print(x)`|`__str__`|`__repr__`, then default |
199
199
|`f"{x}"` (no spec) |`__str__`| same as `str(x)`|
200
200
|`f"{x:spec}"`|`__format__`| built-in format spec engine |
201
-
|`f"{x!r}"`|`__repr__`|,|
201
+
|`f"{x!r}"`|`__repr__`| —|
202
202
203
203
`__format__(spec)` receives the spec string and must return `str`.
204
204
@@ -225,7 +225,7 @@ Existing attributes bypass `__getattr__`; only misses trigger it.
225
225
226
226
## Context managers
227
227
228
-
`with cm() as x:` invokes `__enter__`; its return binds to `as`. On exit, `__exit__(exc_type, exc_value, traceback)` runs,`(None, None, None)` for normal exit, live exception info on raise. Truthy return suppresses; falsy propagates.
228
+
`with cm() as x:` invokes `__enter__`; its return binds to `as`. On exit, `__exit__(exc_type, exc_value, traceback)` runs —`(None, None, None)` for normal exit, live exception info on raise. Truthy return suppresses; falsy propagates.
229
229
230
230
```python
231
231
classSuppress:
@@ -243,7 +243,7 @@ print("after")
243
243
after
244
244
```
245
245
246
-
Multiple managers (`with a(), b() as x:`) nest LIFO,`b` enters last, exits first. Each has its own implicit handler, so inner suppression still lets outer managers run their normal `__exit__(None, None, None)`.
246
+
Multiple managers (`with a(), b() as x:`) nest LIFO —`b` enters last, exits first. Each has its own implicit handler, so inner suppression still lets outer managers run their normal `__exit__(None, None, None)`.
247
247
248
248
If `__exit__` itself raises, the new exception replaces the original.
0 commit comments