mirror of
https://github.com/satwikkansal/wtfpython
synced 2024-11-22 02:54:25 +01:00
Translate Methods equality and identity example
This commit is contained in:
parent
a32eaca58f
commit
6e246d1487
102
translations/README-ru.md
vendored
102
translations/README-ru.md
vendored
@ -1075,3 +1075,105 @@ False
|
|||||||
* Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/).
|
* Более подробное объяснение можно найти [здесь] (https://www.naftaliharris.com/blog/python-subclass-intransitivity/).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
### ▶ Равенство и тождество методов
|
||||||
|
<!-- Example ID: 94802911-48fe-4242-defa-728ae893fa32 --->
|
||||||
|
|
||||||
|
1.
|
||||||
|
```py
|
||||||
|
class SomeClass:
|
||||||
|
def method(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def classm(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def staticm():
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
Обращаясь к `classm` дважды, мы получаем одинаковый объект, но не *тот же самый*? Давайте посмотрим, что происходит
|
||||||
|
с экземплярами `SomeClass`:
|
||||||
|
|
||||||
|
2.
|
||||||
|
```py
|
||||||
|
o1 = SomeClass()
|
||||||
|
o2 = SomeClass()
|
||||||
|
```
|
||||||
|
|
||||||
|
**Вывод:**
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
Повторный доступ к `классу` или `методу` создает одинаковые, но не *те же самые* объекты для одного и того же экземпляра `какого-либо класса`.
|
||||||
|
|
||||||
|
#### 💡 Объяснение
|
||||||
|
* Функции являются [дескрипторами](https://docs.python.org/3/howto/descriptor.html). Всякий раз, когда к функции обращаются как к
|
||||||
|
атрибута, вызывается дескриптор, создавая объект метода, который "связывает" функцию с объектом, владеющим атрибутом. При вызове метод вызывает функцию, неявно передавая связанный объект в качестве первого аргумента
|
||||||
|
(именно так мы получаем `self` в качестве первого аргумента, несмотря на то, что не передаем его явно).
|
||||||
|
```py
|
||||||
|
>>> o1.method
|
||||||
|
<bound method SomeClass.method of <__main__.SomeClass object at ...>>
|
||||||
|
```
|
||||||
|
* При многократном обращении к атрибуту каждый раз создается объект метода! Поэтому `o1.method is o1.method` всегда ложно. Однако доступ к функциям как к атрибутам класса (в отличие от экземпляра) не создает методов; поэтому
|
||||||
|
`SomeClass.method is SomeClass.method` является истинным.
|
||||||
|
```py
|
||||||
|
>>> SomeClass.method
|
||||||
|
<function SomeClass.method at ...>
|
||||||
|
```
|
||||||
|
* `classmethod` преобразует функции в методы класса. Методы класса - это дескрипторы, которые при обращении к ним создают
|
||||||
|
объект метода, который связывает *класс* (тип) объекта, а не сам объект.
|
||||||
|
```py
|
||||||
|
>>> o1.classm
|
||||||
|
<bound method SomeClass.classm of <class '__main__.SomeClass'>>
|
||||||
|
```
|
||||||
|
* В отличие от функций, `classmethod` будет создавать метод и при обращении к нему как к атрибуту класса (в этом случае они
|
||||||
|
привязываются к классу, а не к его типу). Поэтому `SomeClass.classm is SomeClass.classm` является ошибочным.
|
||||||
|
```py
|
||||||
|
>>> SomeClass.classm
|
||||||
|
<bound method SomeClass.classm of <class '__main__.SomeClass'>>
|
||||||
|
```
|
||||||
|
* Объект-метод равен, если обе функции равны, а связанные объекты одинаковы. Поэтому
|
||||||
|
`o1.method == o1.method` является истинным, хотя и не является одним и тем же объектом в памяти.
|
||||||
|
* `staticmethod` преобразует функции в дескриптор "no-op", который возвращает функцию как есть. Методы-объекты
|
||||||
|
никогда не создается, поэтому сравнение с `is` является истинным.
|
||||||
|
```py
|
||||||
|
>>> o1.staticm
|
||||||
|
<function SomeClass.staticm at ...>
|
||||||
|
>>> SomeClass.staticm
|
||||||
|
<function SomeClass.staticm at ...>
|
||||||
|
```
|
||||||
|
* Необходимость создавать новые объекты "метод" каждый раз, когда Python вызывает методы экземпляра, и необходимость изменять аргументы
|
||||||
|
каждый раз, чтобы вставить `self`, сильно сказывается на производительности.
|
||||||
|
CPython 3.7 [решил эту проблему](https://bugs.python.org/issue26110), введя новые опкоды, которые работают с вызовом методов
|
||||||
|
без создания временных объектов методов. Это используется только при фактическом вызове функции доступа, так что
|
||||||
|
приведенные здесь фрагменты не затронуты и по-прежнему генерируют методы :)
|
||||||
|
|
||||||
|
---
|
||||||
|
Loading…
Reference in New Issue
Block a user