[Python-Dev] assigning a custom mapping type to __dict__

Steven Bethard steven.bethard at gmail.com
Wed Mar 2 18:20:37 CET 2005


I think the behavior when supplying a custom mapping type to __dict__
is a little confusing.  I'd like to supply a patch, but I'm not sure
what the preferred solution is.

Let me explain the problem a little first.

For a custom mapping type that does not inherit from dict, Python
gives a nice error message when it's assigned to __dict__:

py> class M(object):
...     def __getitem__(self, key):
...         return 42
... 
py> class O(object):
...    pass
...   
py> o = O()
py> o.__dict__ = M()
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
TypeError: __dict__ must be set to a dictionary

However, a subclass of dict will still be accepted, but has some
confusing behavior -- a redefined __getitem__ is not actually invoked:

py> class M(dict):
...     def __getitem__(self, key):
...         return 42
... 
py> class O(object):
...    pass
... 
py> o = O()
py> o.__dict__ = M()
py> o.a
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
AttributeError: 'O' object has no attribute 'a'

By overriding __getattribute__ in the object's class, you can get the
expected behavior:

py> class M(dict):
...     def __getitem__(self, key):
...         return 42
... 
py> class O(object):
...     def __getattribute__(self, name):
...         getattribute = super(O, self).__getattribute__
...         if not name.startswith('__') or not name.endswith('__'):
...             try:
...                 return getattribute('__dict__')[name]
...             except KeyError:
...                 raise AttributeError(name)
...         return getattribute(name)
... 
py> o = O()
py> o.__dict__ = M()
py> o.a
42
py> o.a = 1
py> o.a
42

So, I see this as a problem, mainly because an error (assiging a
mapping to __dict__ and expecting its methods to be called) passes
silently.  I guess the first question is, do others agree this is also
an problem?

If so, I see a few solutions, and I'd like some input on which is most
desirable.

(1)  Raise an exception when a subclass of dict is assigned to
__dict__.  This is probably the simplest solution (I assume it's
basically just changing a PyDict_Check to a PyDict_CheckExact), and it
keeps the error from passing silently, but it is
backwards-incompatible.  (Classes like my last versions of M and O
above will be broken.)

(2) Allow sublcasses of dict to be assigned to __dict__, but change
the implementation to call the subclass methods, not the dict methods.
 I don't know exactly what needs to be changed to make this work.

(3) Allow any mapping type to be assigned to __dict__, and change the
implementation to use Py_Mapping* calls instead.

I don't know the implementation well enough to know the consequences
of the last two, so I'm hoping for some feedback here.

Thanks!

Steve
-- 
You can wordify anything if you just verb it.
        --- Bucky Katt, Get Fuzzy


More information about the Python-Dev mailing list