伪序列对象:终止所需的异常?

时间:2017-08-10 09:19:54

标签: python python-2.7

我遵循这样的假设:定义_ _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这样的异常才能终止。

这是正确的,在哪里可以找到它?

2 个答案:

答案 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将尝试访问从0infinite的所有索引,因此如果您没有指定何时停止它将继续调用该方法。

只需检查索引值是否高于大小,例如:

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