Цікаво, чому клас __dict__
- це mappingproxy
, а екземпляр __dict__
- це простоdict
>>> class A:
... pass
>>> a = A()
>>> type(a.__dict__)
<class 'dict'>
>>> type(A.__dict__)
<class 'mappingproxy'>
Відповіді:
Це допомагає інтерпретатору запевнити, що ключі для атрибутів та методів класу можуть бути лише рядками.
В іншому, Python є "мовою дорослих, що погоджується", що означає, що користувачі можуть розкривати та змінювати диктовки для об'єктів. Однак у випадку атрибутів та методів класу на рівні класів, якщо ми можемо гарантувати, що ключі є рядками, ми можемо спростити та пришвидшити загальний код справи для пошуку атрибутів та методів на рівні класу. Зокрема, __mro__ логіка пошуку для класів нового стилю спрощується та пришвидшується, вважаючи, що клавіші dict класу є рядками.
type.__setattr__
(що, сподіваємось, / можливо, досить невеликий набір), оскільки ви не можете писати __dict__
; ви повинні використовувати super()
.
gc.get_referents(FooClass.__dict__)[0]['__eq__'] = eqmethod
, екземпляри FooClass
можуть насправді не використовуватись eqmethod
для ==
порівняння.
Картографуючий проксі - це просто дикт без __setattr__
методу.
Ви можете ознайомитися з цим кодом і звернутися до нього.
from types import MappingProxyType
d={'key': "value"}
m = MappingProxyType(d)
print(type(m)) # <class 'mappingproxy'>
m['key']='new' #TypeError: 'mappingproxy' object does not support item assignment
mappingproxy - це версія Python 3.3. Наступний код показує типи dict:
class C:pass
ci=C()
print(type(C.__dict__)) #<class 'mappingproxy'>
print(type(ci.__dict__)) #<class 'dict'>
Оскільки mappingproxy
тип Python 3.3 було перейменовано з dictproxy
. На цю тему відбулася цікава дискусія .
Трохи важко знайти документацію для цього типу, але документація для методу vars це прекрасно описує (хоча деякий час це не документувалось ):
Такі об'єкти, як модулі та екземпляри, мають
__dict__
атрибут, що оновлюється ; однак інші об'єкти можуть мати обмеження на запис щодо своїх__dict__
атрибутів (наприклад, класи використовують type.MappingProxyType для запобігання прямим оновленням словника).
Якщо вам потрібно призначити новий атрибут класу, який ви могли б використовувати setattr
. Варто зазначити, що mappingproxy
JSON не можна серіалізувати. Перевірте проблему, щоб зрозуміти, чому.
Також історія цього типу досить цікава:
Python 2.7: type(A.__dict__)
повертається <type 'dict'>
як type(dict())
, і можливо призначити нові атрибути через __dict__
, наприклад
A.__dict__['foo'] = 'bar'
.
Python 3.0 - 3.2: type(A.__dict__)
повертається <class 'dict_proxy'>
, різниця тепер трохи чіткіша. Спроба призначити новий атрибут дає TypeError
. Була спроба додати dictproxy
як загальнодоступний вбудований тип.
<class 'mappingproxy'>
тип, описаний вище.
mappingproxy
робитьclass.__dict__
лише для читання, так що цеclass.__setattr__
залишається лише способом встановлення атрибутів класу, і саме цей метод застосовує обмеження .