As part of some WSGI middleware I want to write a python class that wraps an iterator to implement a close method on the iterator.
This works fine when I try it with an
What you're trying to do makes sense, but there's something evil going on inside Python here.
class foo(object):
c = 0
def __init__(self):
self.next = self.next2
def __iter__(self):
return self
def next(self):
if self.c == 5: raise StopIteration
self.c += 1
return 1
def next2(self):
if self.c == 5: raise StopIteration
self.c += 1
return 2
it = iter(foo())
# Outputs: >
print it.next
# 2
print it.next()
# 1?!
for x in it:
print x
foo() is an iterator which modifies its next method on the fly--perfectly legal anywhere else in Python. The iterator we create, it, has the method we expect: it.next is next2. When we use the iterator directly, by calling next(), we get 2. Yet, when we use it in a for loop, we get the original next, which we've clearly overwritten.
I'm not familiar with Python internals, but it seems like an object's "next" method is being cached in tp_iternext
(http://docs.python.org/c-api/typeobj.html#tp_iternext), and then it's not updated when the class is changed.
This is definitely a Python bug. Maybe this is described in the generator PEPs, but it's not in the core Python documentation, and it's completely inconsistent with normal Python behavior.
You could work around this by keeping the original next function, and wrapping it explicitly:
class IteratorWrapper2(object):
def __init__(self, otheriter):
self.wrapped_iter_next = otheriter.next
def __iter__(self):
return self
def next(self):
return self.wrapped_iter_next()
for j in IteratorWrapper2(iter([1, 2, 3])):
print j
... but that's obviously less efficient, and you should not have to do that.