我的假设是,定义 _ _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 协议(protocol),似乎需要像 IndexError 或 StopIteration 这样的异常来终止。
这是否正确,在哪里可以找到它的记录?
最佳答案
回答
是的,需要一个IndexError 来终止。
文档
请参阅 __getitem__() 的文档其中有注释:
Note for loops expect that an IndexError will be raised for illegal indexes to allow proper detection of the end of the sequence.
底层源码
创建迭代器的逻辑在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
关于python - 伪序列对象 : Exception needed to terminate?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45609473/