How to dynamically override __setitem__? (no subclass)

I cannot override some of the built-in functions, such as '__setitem__', in Python2.7 (although the same thing happened in previous versions that I tested)

Although I know this is easy to do with a subclass, this is not what I want here, I need to be able to dynamically override these methods.

Apparently, when my class is a subclass of the object , the overridden method always ends the call to the original, but when my class is not <the object ', it works:

>>> def new_implementation(k, v): ... print 'New implementation' ... ### class that extends object >>> class ExtendsObject(object): ... def __setitem__(self, k, v): ... print 'ExtendsObject implementation' ... ### Checking implementation >>> obj = ExtendsObject() >>> obj[0]=0 ExtendsObject implementation ### trying to override setitem, no success >>> obj.__setitem__ = new_implementation >>> obj[0]=0 ExtendsObject implementation ### class that does NOT extends object >>> class DoesNotExtend: ... def __setitem__(self, k, v): ... print 'DoesNotExtend implementation' ... ### Checking implementation >>> obj_2 = DoesNotExtend() >>> obj_2[0]=0 DoesNotExtend implementation ### overriding now works! >>> obj_2.__setitem__ = new_implementation >>> obj_2[0]=0 New implementation 

For some reason, it seems that objects use several different resolution methods for these built-in functions.

This is mistake? Am I doing something wrong?

+4
source share
2 answers

For old-style classes, special methods were scanned by the instance each time they were needed. New style classes look for special methods for the type of instance, not the instance dictionary itself, so you see the behavior that you see.

(If you don’t know, a new-style class is a class directly or indirectly derived from object .)

+5
source

Like Sven Marnach , the problem is that for new-style classes, indexed assignment uses the __setitem__ defined by the class. But it is not difficult to get around this problem. A solution, as often happens, involves yet another level of indirection . This is not a great design, but it seems like an obvious way to do what you want:

 >>> class Foo(object): ... def __setitem__(self, k, v): ... return self._instance_setitem(k, v) ... def _instance_setitem(self, k, v): ... print 'old setitem' ... >>> def new_setitem(self, k, v): ... print 'new setitem' ... >>> f[0] = 0 old setitem >>> f._instance_setitem = types.MethodType(new_setitem, f, Foo) >>> f[0] = 0 new setitem 
+2
source

Source: https://habr.com/ru/post/1396447/


All Articles