python – 伪序列对象:终止需要异常?

我生活在假设中,定义_ _len _ _和_ _getitem_ _方法对于一个类就足够了,所以它的实例可以通过实例中的for元素迭代,直到它被违反了一个例子.我的原始代码完全不同,但这显示了很好地进入无限循环的问题:

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这样的异常才能终止.

这是正确的,在哪里找到它记录?

最佳答案 回答

是的,需要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
点赞