mirror of
https://github.com/satwikkansal/wtfpython
synced 2024-11-22 02:54:25 +01:00
parent
902ca179eb
commit
f13b98e6d5
2
CONTRIBUTORS.md
vendored
2
CONTRIBUTORS.md
vendored
@ -21,7 +21,7 @@ Following are the wonderful people (in no specific order) who have contributed t
|
|||||||
| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96)
|
| Ghost account | N/A | [#96](https://github.com/satwikkansal/wtfpython/issues/96)
|
||||||
| koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) |
|
| koddo | [koddo](https://github.com/koddo) | [#80](https://github.com/satwikkansal/wtfpython/issues/80), [#73](https://github.com/satwikkansal/wtfpython/issues/73) |
|
||||||
| jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) |
|
| jab | [jab](https://github.com/jab) | [#77](https://github.com/satwikkansal/wtfpython/issues/77) |
|
||||||
| Jongy | [Jongy](https://github.com/Jongy) | [#208](https://github.com/satwikkansal/wtfpython/issues/208), [#210](https://github.com/satwikkansal/wtfpython/issues/210) |
|
| Jongy | [Jongy](https://github.com/Jongy) | [#208](https://github.com/satwikkansal/wtfpython/issues/208), [#210](https://github.com/satwikkansal/wtfpython/issues/210), [#233](https://github.com/satwikkansal/wtfpython/issues/233) |
|
||||||
| Diptangsu Goswami | [diptangsu](https://github.com/diptangsu) | [#193](https://github.com/satwikkansal/wtfpython/issues/193) |
|
| Diptangsu Goswami | [diptangsu](https://github.com/diptangsu) | [#193](https://github.com/satwikkansal/wtfpython/issues/193) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
79
README.md
vendored
79
README.md
vendored
@ -44,6 +44,7 @@ So, here we go...
|
|||||||
+ [▶ The sticky output function](#-the-sticky-output-function)
|
+ [▶ The sticky output function](#-the-sticky-output-function)
|
||||||
+ [▶ The chicken-egg problem *](#-the-chicken-egg-problem-)
|
+ [▶ The chicken-egg problem *](#-the-chicken-egg-problem-)
|
||||||
+ [▶ Subclass relationships](#-subclass-relationships)
|
+ [▶ Subclass relationships](#-subclass-relationships)
|
||||||
|
+ [▶ Methods equality and identity](#-methods-equality-and-identity)
|
||||||
+ [▶ All-true-ation *](#-all-true-ation-)
|
+ [▶ All-true-ation *](#-all-true-ation-)
|
||||||
+ [▶ The surprising comma](#-the-surprising-comma)
|
+ [▶ The surprising comma](#-the-surprising-comma)
|
||||||
+ [▶ Strings and the backslashes](#-strings-and-the-backslashes)
|
+ [▶ Strings and the backslashes](#-strings-and-the-backslashes)
|
||||||
@ -1122,6 +1123,84 @@ The Subclass relationships were expected to be transitive, right? (i.e., if `A`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### ▶ Methods equality and identity
|
||||||
|
<!-- Example ID: 94802911-48fe-4242-defa-728ae893fa32 --->
|
||||||
|
|
||||||
|
1.
|
||||||
|
```py
|
||||||
|
class SomeClass:
|
||||||
|
def method(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def classm(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def staticm():
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
```py
|
||||||
|
>>> print(SomeClass.method is SomeClass.method)
|
||||||
|
True
|
||||||
|
>>> print(SomeClass.classm is SomeClass.classm)
|
||||||
|
False
|
||||||
|
>>> print(SomeClass.classm == SomeClass.classm)
|
||||||
|
True
|
||||||
|
>>> print(SomeClass.staticm is SomeClass.staticm)
|
||||||
|
True
|
||||||
|
```
|
||||||
|
|
||||||
|
Accessing `classm` twice, we get an equal object, but not the *same* one? Let's see what happens
|
||||||
|
with instances of `SomeClass`:
|
||||||
|
|
||||||
|
2.
|
||||||
|
```py
|
||||||
|
o1 = SomeClass()
|
||||||
|
o2 = SomeClass()
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
```py
|
||||||
|
>>> print(o1.method == o2.method)
|
||||||
|
False
|
||||||
|
>>> print(o1.method == o1.method)
|
||||||
|
True
|
||||||
|
>>> print(o1.method is o1.method)
|
||||||
|
False
|
||||||
|
>>> print(o1.classm is o1.classm)
|
||||||
|
False
|
||||||
|
>>> print(o1.classm == o1.classm == o2.classm == SomeClass.classm)
|
||||||
|
True
|
||||||
|
>>> print(o1.staticm is o1.staticm is o2.staticm is SomeClass.staticm)
|
||||||
|
True
|
||||||
|
```
|
||||||
|
|
||||||
|
Accessing` classm` or `method` twice, creates equal but not *same* objects for the same instance of `SomeClass`.
|
||||||
|
|
||||||
|
#### 💡 Explanation
|
||||||
|
* Functions are [descriptors](https://docs.python.org/3/howto/descriptor.html). Whenever a function is accessed as an
|
||||||
|
attribute, the descriptor is invoked, creating a method object which "binds" the function with the object owning the
|
||||||
|
attribute. If called, the method calls the function, implicitly passing the bound object as the first argument
|
||||||
|
(this is how we get `self` as the first argument, despite not passing it explicitly).
|
||||||
|
* Accessing the attribute multiple times creates multiple method objects! Therefore `o1.method is o2.method` is
|
||||||
|
never truthy. Accessing functions as class attributes (as opposed to instance) does not create methods, however; so
|
||||||
|
`SomeClass.method is SomeClass.method` is truthy.
|
||||||
|
* `classmethod` transforms functions into class methods. Class methods are descriptors that, when accessed, create
|
||||||
|
a method object which binds the *class* (type) of the object, instead of the object itself.
|
||||||
|
* Unlike functions, `classmethod`s will create a method also when accessed as class attributes (in which case they
|
||||||
|
bind the class, not to the type of it). So `SomeClass.classm is SomeClass.classm` is falsy.
|
||||||
|
* A method object compares equal when both the functions are equal, and the bound objects are the same. So
|
||||||
|
`o1.method == o1.method` is truthy, although not the same object in memory.
|
||||||
|
* `staticmethod` transforms functions into a "no-op" descriptor, which returns the function as-is. No method
|
||||||
|
objects are ever created, so comparison with `is` is truthy.
|
||||||
|
* Having to create new "method" objects every time Python calls instance methods affected performance badly.
|
||||||
|
CPython 3.7 [solved it](https://bugs.python.org/issue26110) by introducing new opcodes that deal with calling methods
|
||||||
|
without creating the temporary method objects. This is used only when the accessed function is actually called, so the
|
||||||
|
snippets here are not affected, and still generate methods :)
|
||||||
|
|
||||||
### ▶ All-true-ation *
|
### ▶ All-true-ation *
|
||||||
|
|
||||||
<!-- Example ID: dfe6d845-e452-48fe-a2da-0ed3869a8042 -->
|
<!-- Example ID: dfe6d845-e452-48fe-a2da-0ed3869a8042 -->
|
||||||
|
Loading…
Reference in New Issue
Block a user