Интересно, почему класс __dict__ является mappingproxy, но экземпляр __dict__ это обычный dict
>>> class A:
... pass
>>> a = A()
>>> type(a.__dict__)
<class 'dict'>
>>> type(A.__dict__)
<class 'mappingproxy'>
Ответ 1
Это помогает интерпретатору гарантировать, что ключи для атрибутов и методов на уровне классов могут быть только строками.
В другом месте Python является "соглашающимся взрослым языком", а это означает, что пользовательский указатель на объекты выставлен и изменен пользователем. Однако в случае атрибутов класса и методов для классов, если мы можем гарантировать, что ключи являются строками, мы можем упростить и ускорить общий код случая для поиска атрибутов и методов на уровне класса. В частности, логика поиска __mro__ для классов нового стиля упрощается и ускоряется, предполагая, что ключи класса dict являются строками.
Ответ 2
Mappingproxy - это просто __setattr__ без метода __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'>