@@ -52,7 +52,6 @@ So, here we go...
52
52
+ [ ▶ Half triple-quoted strings] ( #-half-triple-quoted-strings )
53
53
+ [ ▶ What's wrong with booleans?] ( #-whats-wrong-with-booleans )
54
54
+ [ ▶ Class attributes and instance attributes] ( #-class-attributes-and-instance-attributes )
55
- + [ ▶ Non-reflexive class method * ] ( #-non-reflexive-class-method- )
56
55
+ [ ▶ yielding None] ( #-yielding-none )
57
56
+ [ ▶ Yielding from... return! * ] ( #-yielding-from-return- )
58
57
+ [ ▶ Nan-reflexivity * ] ( #-nan-reflexivity- )
@@ -1185,18 +1184,41 @@ Accessing` classm` or `method` twice, creates equal but not *same* objects for t
1185
1184
attribute, the descriptor is invoked, creating a method object which " binds" the function with the object owning the
1186
1185
attribute. If called, the method calls the function, implicitly passing the bound object as the first argument
1187
1186
(this is how we get `self ` as the first argument, despite not passing it explicitly).
1188
- * Accessing the attribute multiple times creates multiple method objects! Therefore `o1.method is o2.method` is
1187
+ ```py
1188
+ >> > o1.method
1189
+ < bound method SomeClass.method of < __main__.SomeClass object at ... >>
1190
+ ```
1191
+ * Accessing the attribute multiple times creates a method object every time! Therefore `o1.method is o1.method` is
1189
1192
never truthy. Accessing functions as class attributes (as opposed to instance) does not create methods, however; so
1190
1193
`SomeClass.method is SomeClass.method` is truthy.
1194
+ ```py
1195
+ >> > SomeClass.method
1196
+ < function SomeClass.method at ... >
1197
+ ```
1191
1198
* `classmethod ` transforms functions into class methods. Class methods are descriptors that, when accessed, create
1192
1199
a method object which binds the * class * (type ) of the object , instead of the object itself.
1200
+ ```py
1201
+ >> > o1.classm
1202
+ < bound method SomeClass.classm of < class ' __main__.SomeClass' >>
1203
+ ```
1193
1204
* Unlike functions, `classmethod ` s will create a method also when accessed as class attributes (in which case they
1194
1205
bind the class , not to the type of it). So `SomeClass.classm is SomeClass.classm` is falsy.
1206
+ ```py
1207
+ >> > SomeClass.classm
1208
+ < bound method SomeClass.classm of < class ' __main__.SomeClass' >>
1209
+ ```
1195
1210
* A method object compares equal when both the functions are equal, and the bound objects are the same. So
1196
1211
`o1.method == o1.method` is truthy, although not the same object in memory.
1197
1212
* `staticmethod ` transforms functions into a " no-op" descriptor, which returns the function as - is . No method
1198
1213
objects are ever created, so comparison with `is ` is truthy.
1199
- * Having to create new " method" objects every time Python calls instance methods affected performance badly.
1214
+ ```py
1215
+ >> > o1.staticm
1216
+ < function SomeClass.staticm at ... >
1217
+ >> > SomeClass.staticm
1218
+ < function SomeClass.staticm at ... >
1219
+ ```
1220
+ * Having to create new " method" objects every time Python calls instance methods and having to modify the arguments
1221
+ every time in order to insert `self ` affected performance badly.
1200
1222
CPython 3.7 [solved it](https:// bugs.python.org/ issue26110) by introducing new opcodes that deal with calling methods
1201
1223
without creating the temporary method objects. This is used only when the accessed function is actually called, so the
1202
1224
snippets here are not affected, and still generate methods :)
@@ -1530,49 +1552,6 @@ True
1530
1552
1531
1553
---
1532
1554
1533
- ### ▶ Non-reflexive class method *
1534
-
1535
- <!-- Example ID: 3649771a-f733-413c-8060-3f9f167b83fd -->
1536
-
1537
- ```py
1538
- class SomeClass:
1539
- def instance_method(self):
1540
- pass
1541
-
1542
- @classmethod
1543
- def class_method(cls):
1544
- pass
1545
- ```
1546
-
1547
- **Output:**
1548
-
1549
- ```py
1550
- >>> SomeClass.instance_method is SomeClass.instance_method
1551
- True
1552
- >>> SomeClass.class_method is SomeClass.class_method
1553
- False
1554
- >>> id(SomeClass.class_method) == id(SomeClass.class_method)
1555
- True
1556
- ```
1557
-
1558
- #### 💡 Explanation:
1559
-
1560
- - The reason `SomeClass.class_method is SomeClass.class_method` is `False` is due to the `@classmethod` decorator.
1561
-
1562
- ```py
1563
- >>> SomeClass.instance_method
1564
- <function __main__.SomeClass.instance_method(self)>
1565
- >>> SomeClass.class_method
1566
- <bound method SomeClass.class_method of <class '__main__.SomeClass'>
1567
- ```
1568
-
1569
- A new bound method every time `SomeClass.class_method` is accessed.
1570
-
1571
- - `id(SomeClass.class_method) == id(SomeClass.class_method)` returned `True` because the second allocation of memory for `class_method` happened at the same location of first deallocation (See Deep Down, we're all the same example for more detailed explanation).
1572
-
1573
- ---
1574
-
1575
-
1576
1555
### ▶ yielding None
1577
1556
<!-- Example ID: 5a40c241-2c30-40d0-8ba9-cf7e097b3b53 --->
1578
1557
```py
0 commit comments