[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