我遵循这样的假设:定义_ _len_ _
和_ _getitem_ _
方法对于一个类就足够了,所以它的实例可以通过for element in instance:
迭代,直到它被违反了例。我的原始代码完全不同,但这显示了很好地进入无限循环的问题:
class Limited(object):
def __init__(self, size=5):
self.size = size
def __len__(self):
return self.size
def __getitem__(self, item):
return item*10
if __name__ == "__main__":
test = Limited(4)
assert len(test) == 4
for q in test:
print q
我找不到对终止迭代循环的要求的具体引用,但是如果不想遵守完整的Iterator协议,似乎需要像IndexError或StopIteration这样的异常才能终止。
这是正确的,在哪里可以找到它?
答案 0 :(得分:5)
是的, IndexError 需要终止。
请参阅__getitem__()的文档,其中包含注释:
注意for循环可能会引发IndexError非法 索引,以便正确检测序列的结束。
创建迭代器的逻辑在Objects / iterobject.c中:
static PyObject *
iter_iternext(PyObject *iterator)
{
seqiterobject *it;
PyObject *seq;
PyObject *result;
assert(PySeqIter_Check(iterator));
it = (seqiterobject *)iterator;
seq = it->it_seq;
if (seq == NULL)
return NULL;
if (it->it_index == PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"iter index too large");
return NULL;
}
result = PySequence_GetItem(seq, it->it_index);
if (result != NULL) {
it->it_index++;
return result;
}
if (PyErr_ExceptionMatches(PyExc_IndexError) ||
PyErr_ExceptionMatches(PyExc_StopIteration))
{
PyErr_Clear();
Py_DECREF(seq);
it->it_seq = NULL;
}
return NULL;
}
要修复OP的代码,只需要在 __ getitem __()方法的开头添加两行:
class Limited(object):
def __init__(self, size=5):
self.size = size
def __len__(self):
return self.size
def __getitem__(self, item):
if item >= len(self):
raise IndexError
return item*10
if __name__ == "__main__":
test = Limited(4)
assert len(test) == 4
for q in test:
print(q)
输出有限序列:
0
10
20
30
答案 1 :(得分:2)
实现__getItem__
方法python将尝试访问从0
到infinite
的所有索引,因此如果您没有指定何时停止它将继续调用该方法。
只需检查索引值是否高于大小,例如:
class Limited(object):
def __init__(self, size=5):
self.size = size
def __len__(self):
return self.size
def __getitem__(self, item):
if item < self.size:
return item*10
raise IndexError
这里有live example