Вы никогда не должны насильственно уничтожать поток, не сотрудничая с ним.
Уничтожение потока удаляет любые гарантии, что блоки попытки/наконец настраивали, таким образом, Вы могли бы оставить блокировки заблокированными, файлы открытый, и т.д.
единственное время можно утверждать, что насильственно уничтожение распараллеливает, хорошая идея, должен закрыть программу быстро, но никогда единственные потоки.
То, что вы пытаетесь сделать, имеет смысл, но здесь что-то злобное творится внутри Python.
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: <bound method foo.next2 of <__main__.foo object at 0xb7d5030c>>
print it.next
# 2
print it.next()
# 1?!
for x in it:
print x
foo () - итератор, который изменяет свой следующий метод на лету - идеально законно где-либо еще в Python. Итератор, который мы создаем, имеет ожидаемый нами метод: it.next is next2. Когда мы используем итератор напрямую, вызывая next (), мы получаем 2. Тем не менее, когда мы используем его в цикле for, мы получаем исходный next, который мы явно перезаписали.
Я не знаком с Внутреннее устройство Python, но похоже, что метод "next" объекта кэшируется в tp_iternext
( http://docs.python.org/c-api/typeobj.html#tp_iternext ), а затем он не обновляется при изменении класса.
Это определенно ошибка Python. Возможно, это описано в PEP генератора, но это '
Просто верните итератор. Для этого нужен __ iter __
. Нет смысла пытаться исправить объект, чтобы он находился в итераторе, и вернуть его, когда у вас уже есть итератор.
РЕДАКТИРОВАТЬ: Теперь с двумя методами. Однажды обезьяна исправляет обернутый итератор, второй - оборачивает итератор.
class IteratorWrapperMonkey(object):
def __init__(self, otheriter):
self.otheriter = otheriter
self.otheriter.close = self.close
def close(self):
print "Closed!"
def __iter__(self):
return self.otheriter
class IteratorWrapperKitten(object):
def __init__(self, otheriter):
self.otheriter = otheriter
def __iter__(self):
return self
def next(self):
return self.otheriter.next()
def close(self):
print "Closed!"
class PatchableIterator(object):
def __init__(self, inp):
self.iter = iter(inp)
def next(self):
return self.iter.next()
def __iter__(self):
return self
if __name__ == "__main__":
monkey = IteratorWrapperMonkey(PatchableIterator([1, 2, 3]))
for i in monkey:
print i
monkey.close()
kitten = IteratorWrapperKitten(iter([1, 2, 3]))
for i in kitten:
print i
kitten.close()
Оба метода работают как с классами нового, так и с классами старого стиля.
Похоже на встроенный iter
не проверяет next
, вызываемый в экземпляре, но в классе, а IteratorWrapper2
не имеет никакого next
. Ниже приведена более простая версия вашей проблемы
class IteratorWrapper2(object):
def __init__(self, otheriter):
self.next = otheriter.next
def __iter__(self):
return self
it=iter([1, 2, 3])
myit = IteratorWrapper2(it)
IteratorWrapper2.next # fails that is why iter(myit) fails
iter(myit) # fails
, поэтому решением было бы вернуть otheriter
в __ iter __
class IteratorWrapper2(object):
def __init__(self, otheriter):
self.otheriter = otheriter
def __iter__(self):
return self.otheriter
или написать свой собственный next
, заключив внутренний итератор
class IteratorWrapper2(object):
def __init__(self, otheriter):
self.otheriter = otheriter
def next(self):
return self.otheriter.next()
def __iter__(self):
return self
Хотя я не понимаю, почему iter
просто не использует self.next
экземпляра.