Method overriding by monkey patching

inheritance, overriding, python

Solution

You cannot monkeypatch either `__iter__(self)` or, by extension, `next(self)` on instances because these methods are treated as class methods instead as a CPython internal optimization (see Special method lookup for new-style classes for an in-depth rationale as to why this is).

If you need to monkeypatch these methods, you'll need to set them directly on the class instead:

class DerivedO(BaseClass):
    def __init__(self):
        self.new_count = 2
        self.__class__.next = self.__class__.new_next

    def new_next(self):
        if self.new_count:
            self.new_count -= 1
            return None
        else:
            raise StopIteration

The above will work; note that I set `__class__.next` to the unbound function `new_next`, not to the bound method.

Problem

I'm trying to figure out why the following example won't work. ``` class BaseClass(object): def __init__(self): self.count = 1 def __iter__(self): return self def next(self): if self.count: self.count -= 1 return self else: raise StopIteration class DerivedNO(BaseClass): pass class DerivedO(BaseClass): def __init__(self): self.new_count = 2 self.next = self.new_next def new_next(self): if self.new_count: self.new_count -= 1 return None else: raise StopIteration x = DerivedNO() y = DerivedO() print x print list(x) print y print list(y) ``` And here is the output: ``` <__main__.DerivedNO object at 0x7fb2af7d1c90> [<__main__.DerivedNO object at 0x7fb2af7d1c90>] <__main__.DerivedO object at 0x7fb2af7d1d10> Traceback (most recent call last): File "playground.py", line 41, in <module> print list(y) File "playground.py", line 11, in next if self.count: AttributeError: 'DerivedO' object has no attribute 'count' ``` As you can see the new method will not be overridden in `DerivedO` when I try to assign the `next()` method in `__init__`. Why is that? A simple call to next will work fine, but not at all when using iterating techniques. Edit: I realize my question wasn't completely clear. The AttributeError isn't the problem I'm looking to solve. But it does show that `next()` is called on `BaseClass` instead of on `DerivedO` as I thought it would.

Original source

Related problems