Class.__class__ magic trick help

Oscar Benjamin oscar.benjamin at bristol.ac.uk
Tue Aug 21 11:43:21 EDT 2012


On 21 August 2012 16:19, Oscar Benjamin <oscar.benjamin at bristol.ac.uk>wrote:

>
> On Aug 21, 2012 3:42 PM, "Massimo DiPierro" <massimo.dipierro at gmail.com>
> wrote:
> >
> > Thanks again Oscar. I cannot do that. I have tight constraints. I am not
> at liberty to modify the code that uses the class. The exposed API cannot
> change including a.x, dict(a), is isinstance(a,dict).
> >
> > My goal it so change the definition of this class to make it faster.
> >
> > Where is in the Python source code is the casting to dict defined? Where
> can I try understand what it does?
>
> help(dict)
>
> There is no cast, there is only the dict constructor. If the dict
> constructor finds a dict instance (including from a subclass) then it will
> efficiently create the new dict from the old dict's underlying data without
> calling your methods. If you want dict(a) and isinstance(dict) to work them
> you need to tell the dict superclass to store the data using
> dict.__setitem__.
>
> You have three options:
> 1) use SlowStorage
> 2) duplicate the data in self and self.__dict__ (this will probably end up
> slowing down FastStorage)
> 3) change the requirement to isinstance(Mapping)
>
> Oscar
>
Okay, there is a way to solve your problem:

>>> class Storage(dict):
...     def __init__(self, *args, **kwargs):
...         dict.__init__(self, *args, **kwargs)
...         self.__dict__ = self
...
>>> s = Storage()
>>> s
{}
>>> s.x = 1
>>> s
{'x': 1}
>>> dict(s)
{'x': 1}
>>> isinstance(s, dict)
True

But it's a stupid idea unless you know that the keys of your dict will
*never* have any of the following values:

>>> dir({})
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__',
'__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items',
'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem',
'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

To see what goes wrong:

>>> s['items'] = [1,2,3]
>>> s.items()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable

Oscar
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20120821/05caccdb/attachment.html>


More information about the Python-list mailing list