Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a class __dict__ a mappingproxy?

I wonder why a class __dict__ is a mappingproxy, but an instance __dict__ is just a plain dict

>>> class A:
...     pass

>>> a = A()
>>> type(a.__dict__)
<class 'dict'>
>>> type(A.__dict__)
<class 'mappingproxy'>
like image 977
José Luis Avatar asked Sep 22 '15 15:09

José Luis


People also ask

What does __ dict __ mean in python?

A special attribute of every module is __dict__. This is the dictionary containing the module's symbol table. object.__dict__ A dictionary or other mapping object used to store an object's (writable) attributes.

What is Mappingproxy?

A mappingproxy is simply a dict with no __setattr__ method. You can check out and refer to this code. 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.

What is a dict attribute?

AttrDict , Attribute Dictionary, is the exact same as a python native dict , except that in most cases, you can use the dictionary key as if it was an object attribute instead. This allows users to create container objects that looks as if they are class objects (as long as the user objects the proper limitations).


3 Answers

This helps the interpreter assure that the keys for class-level attributes and methods can only be strings.

Elsewhere, Python is a "consenting adults language", meaning that dicts for objects are exposed and mutable by the user. However, in the case of class-level attributes and methods for classes, if we can guarantee that the keys are strings, we can simplify and speed-up the common case code for attribute and method lookup at the class-level. In particular, the __mro__ search logic for new-style classes is simplified and sped-up by assuming the class dict keys are strings.

like image 68
Raymond Hettinger Avatar answered Oct 17 '22 23:10

Raymond Hettinger


A mappingproxy is simply a dict with no __setattr__ method.

You can check out and refer to this code.

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 is since Python 3.3. The following code shows dict types:

class C:pass
ci=C()
print(type(C.__dict__)) #<class 'mappingproxy'>
print(type(ci.__dict__)) #<class 'dict'>
like image 17
prosti Avatar answered Oct 18 '22 00:10

prosti


Since Python 3.3 mappingproxy type was renamed from dictproxy. There was an interesting discussion on this topic.

It's a little bit hard to find the documentation for this type, but the documentation for vars method describes this perfectly (though it wasn't documented for a while):

Objects such as modules and instances have an updateable __dict__ attribute; however, other objects may have write restrictions on their __dict__ attributes (for example, classes use a types.MappingProxyType to prevent direct dictionary updates).

If you need to assign a new class attribute you could use setattr. It worth to note that mappingproxy is not JSON serializable, check out the issue to understand why.


Also the history of this type is a quite interesting:

  • Python 2.7: type(A.__dict__) returns <type 'dict'> as type(dict()), and it's possible to assign new attributes through __dict__, e.g. A.__dict__['foo'] = 'bar'.
  • Python 3.0 - 3.2: type(A.__dict__) returns <class 'dict_proxy'>, the difference is introduced. Trying to assign a new attribte gives TypeError. There was an attempt to add dictproxy as a public built-in type.
  • Python 3.3: adds the <class 'mappingproxy'> type described above.
like image 15
funnydman Avatar answered Oct 18 '22 00:10

funnydman