[Python-Dev] inconsistency when swapping obj.__dict__ with a
dict-like object...
Nick Coghlan
ncoghlan at gmail.com
Wed Apr 6 13:31:44 CEST 2005
> P.S. (IMHO) the type check here is not that necessary (at least in its
> current state), as what we need to assert is not the relation to the
> dict class but the support of the mapping protocol....
The type-check is basically correct - as you have discovered, type & object use
the PyDict_* API internally (for speed reasons, as I understand it), so
supporting the mapping API is not really sufficient for something assigned to
__dict__. Changing this for exec is one thing, as speed of access to the locals
dict isn't likely to have a major impact on the overall performance of such
code, but I would expect changing class dictionary access code in a similar way
would have a major (detrimental) performance impact.
Depending on the use case, it is possible to work around the problem by defining
__dict__, __getattribute__, __setattr__ and __delattr__ in the class. defining
__dict__ sidesteps the type error, defining the other three methods then let's
you get around the fact that the standard C-level dict pointer is no longer
being updated, as well as making sure the general mapping API is used, rather
than the concrete PyDict_* API. This is kinda ugly, but it works as long as any
C code using the class __dict__ goes via the attribute access machinery and
doesn't try to get the dictionary automatically supplied by Python by digging
directly into the type structure.
=====================
from UserDict import DictMixin
class Dict(DictMixin):
def __init__(self, dct=None):
if dct is None:
dct = {}
self._dict = dct
def __getitem__(self, name):
return self._dict[name]
def __setitem__(self, name, value):
self._dict[name] = value
def __delitem__(self, name):
del self._dict[name]
def keys(self):
return self._dict.keys()
class A(object):
def __new__(cls, *p, **n):
o = object.__new__(cls)
super(A, o).__setattr__('__dict__', Dict())
return o
__dict__ = None
def __getattr__(self, attr):
try:
return self.__dict__[attr]
except KeyError:
raise AttributeError("%s" % attr)
def __setattr__(self, attr, value):
if attr in self.__dict__ or not hasattr(self, attr):
self.__dict__[attr] = value
else:
super(A, self).__setattr__(attr, value)
def __delattr__(self, attr):
if attr in self.__dict__:
del self.__dict__[attr]
else:
super(A, self).__delattr__(attr)
Py> a = A()
Py> a.__dict__._dict
{}
Py> a.xxx = 123
Py> a.__dict__._dict
{'xxx': 123}
Py> a.__dict__._dict['yyy'] = 321
Py> a.yyy
321
Py> a.__dict__._dict
{'xxx': 123, 'yyy': 321}
Py> del a.xxx
Py> a.__dict__._dict
{'yyy': 321}
Py> del a.xxx
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 21, in __delattr__
AttributeError: xxx
Py> a.__dict__ = {}
Py> a.yyy
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 11, in __getattr__
AttributeError: yyy
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
More information about the Python-Dev
mailing list