Если у меня есть класс с интерфейсом:
class AnIteratable(object):
def __init__(self):
#initialize data structure
def add(self, obj):
# add object to data structure
def __iter__(self):
#return the iterator
def next(self):
# return next object
... как бы я настроил все так, чтобы, если add()
вызывался в середине итерации, возникало исключение, подобное:
In [14]: foo = {'a': 1}
In [15]: for k in foo:
....: foo[k + k] = 'ohnoes'
....:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-15-2e1d338a456b> in <module>()
----> 1 for k in foo:
2 foo[k + k] = 'ohnoes'
3
RuntimeError: dictionary changed size during iteration
Обновление. Если интерфейсу нужны дополнительные методы, добавьте их. Я также удалил реализацию __iter__()
.
Обновление №2 На основе ответа Киндалла я смоделировал следующую псевдореализацию. Обратите внимание, что _datastruture и связанные с ним методы, индексирующие его, являются абстракциями, и автору класса придется написать свои собственные механизмы обхода структуры данных и указателей местоположения.
class AnIteratable(object):
def __init__(self):
self._itercount = 0
self._datastructure = init_data_structure() #@UndefinedVariable
# _datastructure, and the methods called on it, are abstractions.
def add(self, obj):
if self._itercount:
raise RuntimeError('Attempt to change object while iterating')
# add object to data structure
def __iter__(self):
self._itercount += 1
return self.AnIterator(self)
class AnIterator(object):
def __init__(self, aniterable):
self._iterable = aniterable
self._currentIndex = -1 #abstraction
self._notExhausted = True
def next(self):
if self._iterable._datastructure.hasNext(self._currentIndex):
self._currentIndex += 1
return self._iterable._datastructure.next(self._currentIndex)
else:
if self._notExhausted:
self._iterable._itercount -= 1
self._notExhausted = False
raise StopIteration
def __next__(self):
return self.next()
# will be called when there are no more references to this object
def __del__(self):
if self._notExhausted:
self._iterable._itercount -= 1
Обновление 3 После прочтения еще немного, кажется, что __del__
, вероятно, не правильный путь. Следующее может быть лучшим решением, хотя оно требует, чтобы пользователь явно освободил не исчерпанный итератор.
def next(self):
if self._notExhausted and
self._iterable._datastructure.hasNext(self._currentIndex):
#same as above from here
def discard(self):
if self._notExhausted:
self._ostore._itercount -= 1
self._notExhausted = False
next
? - person David Robinson   schedule 18.09.2012foo
являетсяdict
, вы можете использоватьfor k in foo.keys()[:]
. В другом случае это зависит от реализации методаnext
. - person Alexey Kachayev   schedule 18.09.2012