9

I'm trying to override an object's next function using the code below (python 2.7).

When the object's next method is called directly, the new function is invoked. However when I call the builtin next() function on my object (which, according to the docs, should call the instance's next method), the ORIGINAL function is invoked.

Can someone explain this behaviour?

class Test(object):
    def __iter__(self):
        return self
    def next(self):
        return 1

test = Test()
def new_next(self):
    return 2

test.next = type(test.__class__.next)(new_next, test, test.__class__)
print test.next() # 2
print next(test) # 1
Tzach
  • 12,889
  • 11
  • 68
  • 115

1 Answers1

6

If I'm reading this source correctly it seems like the iterator is set when the class is defined. I might read it wrong though. I'm guessing it's for fast lookup of the next function (setting it as a slot) since it's used in loops etc.

Given that, the following seems to do what you're after:

>>> test.__class__.next = type(test.__class__.next)(new_next, test, test.__class__)
>>> next(test)
2
André Laszlo
  • 15,169
  • 3
  • 63
  • 81
  • Thanks! I actually ended up with a different approach, when I dynamically create a class that inherits from Test, and override the next method there. This way I'm not changing the original class. – Tzach Jan 05 '17 at 15:51
  • Sounds safer somehow, instead of relying on some undocumented behavior and some guy half-guessing on SO :) Very interesting though, thanks for posting. – André Laszlo Jan 05 '17 at 15:55
  • 2
    http://stackoverflow.com/questions/34490998/why-typex-enter-x-instead-of-x-enter-in-python-standard-context/34491119#34491119 https://docs.python.org/3/reference/datamodel.html#special-method-lookup – warvariuc Jan 06 '17 at 06:11