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

Arnaud Delobelle arnodel at googlemail.com
Fri Dec 5 15:27:27 EST 2008


Arnaud Delobelle <arnodel at googlemail.com> writes:

> "Zac Burns" <zac256 at gmail.com> writes:
>
>> Ok. Feature request then - assignment of a special method name to an
>> instance raises an error.
>
> I haven't got the time to implement it, but I'm sure you can obtain the
> behaviour you want.

OK I've had half an hour to fill this afternoon so I tried to implement
it.  I've restriced the ability to override special methods to
__getitem__ but this could be extended to any special method AFAICS.  It
combines a metaclass and two descriptors (one for the metaclass and one
for the class), there may be a simpler way!  It is proof-of-concept
code, I have not tried to make it behave sensibly when no __getitem__
method is defined (although that would be straighforward) and I have not
thought about how it would work with (multiple) inheritance (this may
require lots more thinking).  Here it is, tested very succintly on
Python 2.5:

class ClassGetItem(object):
    def __get__(self, obj, objtype=None):
        return obj._getitem_
    def __set__(self, obj, val):
        obj._getitem_ = val

class GetItem(object):
    def __get__(self, obj, objtype=None):
        return obj._getitem_
    def __set__(self, obj, val):
        obj._getitem_ = val

class MetaOverrideSpecial(type):
    def __new__(meta, name, bases, attrs):
        if '__getitem__' in attrs:
            attrs['_getitem_'] = attrs['__getitem__']
        attrs['__getitem__'] = GetItem()
        return type.__new__(meta, name, bases, attrs)
    __getitem__ = ClassGetItem()

class OverrideSpecial(object):
    __metaclass__ = MetaOverrideSpecial


Here is an example that shows it in action:

>>> class Foo(OverrideSpecial):
...     def __getitem__(self, key): return 'Class getitem(%s)' % key
... 
>>> foo=Foo()
>>> foo[3]
'Class getitem(3)'

Override the class's __getitem__ special method:

>>> Foo.__getitem__ = lambda self, key: 'Overriden class getitem(%s)' % key
>>> foo['bar']
'Overriden class getitem(bar)'

Override the instance's __getitem__ special method:

>>> foo.__getitem__ = lambda key: 'Instance getitem(%s)' % key
>>> foo['baz']
'Instance getitem(baz)'

What-a-way-to-waste-time'ly yours

-- 
Arnaud



More information about the Python-list mailing list