Overriding a method at the instance level on a subclass of a builtin type

Jason Scheirer jason.scheirer at gmail.com
Wed Dec 3 20:25:29 CET 2008


On Dec 2, 6:13 pm, Aaron Brady <castiro... at gmail.com> wrote:
> On Dec 2, 6:58 pm, "Zac Burns" <zac... at gmail.com> wrote:
>
>
>
> > Sorry for the long subject.
>
> > I'm trying to create a subclass dictionary that runs extra init code
> > on the first __getitem__ call. However, the performance of __getitem__
> > is quite important - so I'm trying in the subclassed __getitem__
> > method to first run some code and then patch in the original dict
> > method for the instance to avoid even the check to see if the init
> > code has been run. Various recipes using instancemethod and the like
> > have failed me.
>
> > Curiously if __slots__ is not specified no error occurs when setting
> > self.__getitem__ but the function is not overriden. If __slots__ is
> > ['__getitem__'] however it complains that __getitem__ is read only. I
> > do not understand that behavior.
>
> > --
> > Zachary Burns
> > (407)590-4814
> > Aim - Zac256FL
> > Production Engineer (Digital Overlord)
> > Zindagi Games
>
> That sounds like the State Pattern, from GoF.  http://en.wikipedia.org/wiki/State_pattern
>
> I like the idea of 'renaming', not redefining, but reassigning methods
> at different points during an object's lifetime.  I often wish I had
> more experience with it, and more docs talked about it.
>
> It's hard on memory usage, since each instance has its own function
> attribute, even if there's still only one instance of the function.
> Without it, the function attribute is just looked up on the class.
>
> Not thoroughly tested:
>
> >>> class A:
>
> ...     def methA( self ):
> ...             print 'methA'
> ...             self.meth= self.methB
> ...     meth= methA
> ...     def methB( self ):
> ...             print 'methB'
> ...>>> a= A()
> >>> a.meth()
> methA
> >>> a.meth()
>
> methB

The problem with using this this pattern in the way that you've
specified is that you have a potential memory leak/object lifetime
issue. Assigning a bound method of an instance (which itself holds a
reference to self) to another attribute in that same instance creates
a kind of circular dependency that I have discovered can trip up the
GC more often than not.

You can subclass it as easily:

class dictsubclass(dict):
    def __getitem__(self, keyname):
        if not hasattr(self, '_run_once'):
            self.special_code_to_run_once()
            self._run_once = True
        return super(self, dict).__getitem__(keyname)

If that extra ~16 bytes associated with the subclass is really a
problem:

class dictsubclass(dict):
    def __getitem__(self, keyname):
        self.special_code_to_run_once()
        self.__class__ = dict
        return super(self, dict).__getitem__(keyname)

But I don't think that's a good idea at all.



More information about the Python-list mailing list