Class.__class__ magic trick help

Oscar Benjamin oscar.benjamin at bristol.ac.uk
Tue Aug 21 09:17:03 EDT 2012


On 21 August 2012 13:52, Massimo Di Pierro <massimo.dipierro at gmail.com>wrote:

> On Aug 21, 2:40 am, Oscar Benjamin <oscar.j.benja... at gmail.com> wrote:
> > On Mon, 20 Aug 2012 21:17:15 -0700 (PDT), Massimo Di Pierro
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > <massimo.dipie... at gmail.com> wrote:
> > > Consider this code:
> > > class SlowStorage(dict):
> > >     def __getattr__(self,key):
> > >           return self[key]
> > >     def __setattr__(self,key):
> > >           self[key]=value
> > > class FastStorage(dict):
> > >     def __init__(self, __d__=None, **kwargs):
> > >         self.update(__d__,**kwargs)
> > >     def __getitem__(self,key):
> > >         return self.__dict__.get(key,None)
> > >     def __setitem__(self,key,value):
> > >         self.__dict__[key] = value
> > >     def __delitem__(self,key):
> > >         delattr(self,key)
> > >     def __copy__(self):
> > >         return Storage(self)
> > >     def __nonzero__(self):
> > >         return len(self.__dict__)>0
> > >     def pop(self,key,default=None):
> > >         if key in self:
> > >             default = getattr(self,key)
> > >             delattr(self,key)
> > >         return default
> > >     def clear(self):
> > >         self.__dict__.clear()
> > >     def __repr__(self):
> > >         return repr(self.__dict__)
> > >     def keys(self):
> > >         return self.__dict__.keys()
> > >     def values(self):
> > >         return self.__dict__.values()
> > >     def items(self):
> > >         return self.__dict__.items()
> > >       def iterkeys(self):
> > >         return self.__dict__.iterkeys()
> > >     def itervalues(self):
> > >         return self.__dict__.itervalues()
> > >     def iteritems(self):
> > >         return self.__dict__.iteritems()
> > >     def viewkeys(self):
> > >         return self.__dict__.viewkeys()
> > >     def viewvalues(self):
> > >         return self.__dict__.viewvalues()
> > >     def viewitems(self):
> > >         return self.__dict__.viewitems()
> > >     def fromkeys(self,S,v=None):
> > >         return self.__dict__.fromkeys(S,v)
> > >     def setdefault(self, key, default=None):
> > >         try:
> > >             return getattr(self,key)
> > >         except AttributeError:
> > >             setattr(self,key,default)
> > >             return default
> > >     def clear(self):
> > >         self.__dict__.clear()
> > >     def len(self):
> > >         return len(self.__dict__)
> > >     def __iter__(self):
> > >         return self.__dict__.__iter__()
> > >     def has_key(self,key):
> > >         return key in self.__dict__
> > >     def __contains__(self,key):
> > >         return key in self.__dict__
> > >     def update(self,__d__=None,**kwargs):
> > >         if __d__:
> > >             for key in __d__:
> > >                 kwargs[key] = __d__[key]
> > >         self.__dict__.update(**kwargs)
> > >     def get(self,key,default=None):
> > >         return getattr(self,key) if key in self else default
> > > >>> s=SlowStorage()
> > > >>> a.x=1  ### (1)
> > > >>> a.x    ### (2)
> > > 1 # ok
> > > >>> isinstance(a,dict)
> > > True # ok
> > > >>> print dict(a)
> > > {'x':1} # ok (3)
> >
> > Try:
> >
> > >>> a.items()
> >
> > What does that show?
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > > >>> s=FastStorage()
> > > >>> a.x=1  ### (4)
> > > >>> a.x    ### (5)
> > > 1 # ok
> > > >>> isinstance(a,dict)
> > > True # ok
> > > >>> print dict(a)
> > > {} # not ok (6)
> > > Lines (4) and (5) are about 10x faster then lines (1) and (2). I
> > like
> > > FastStorage better but while (3) behaves ok, (6) does not behave as
> > I
> > > want.
> > > I intuitively understand why FastStorage is cannot cast into dict
> > > properly.
> > > What I do not know is how to make it do the casting properly without
> > > losing the 10x speedup of FastStorage over SlowStorage.
> > > Any idea?
> >
> > I don't really understand what your trying to do but since you didn't
> > add the __setattr__ method to FastStorage the item is not added to
> > the dictionary when you do a.x = 1
> >
> > Oscar
>
> >>> a.items()
> [('x',1')]
>
> all the APIs work as expected except casting to dict.
> --
> http://mail.python.org/mailman/listinfo/python-list
>

Sorry, I see what you're doing now. Because you've subclassed dict the dict
constructor is not using any of the python methods you have defined to
create a new dict. It is copying directly from the builtin instance that
your instance is wrapping, but you haven't actually passed your values on
to the superclass so it hasn't stored them in the builtin data structure.

Either subclass object so that your methods are called, or do something
like:

def __setitem__(self,key,value):
    self.__dict__[key] = value
    dict.__setitem__(self, key, value)

I still don't see the point of this but that should work.

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


More information about the Python-list mailing list