即使正则表达式匹配对象实现了__getitem__,它怎么也不会被迭代?

时间:2018-09-16 19:11:40

标签: python iterable

您可能知道,implementing a __getitem__ method makes a class iterable

class IterableDemo:
    def __getitem__(self, index):
        if index > 3:
            raise IndexError

        return index

demo = IterableDemo()
print(demo[2])  # 2
print(list(demo))  # [0, 1, 2, 3]
print(hasattr(demo, '__iter__'))  # False

但是,这不适用于正则表达式匹配对象:

>>> import re
>>> match = re.match('(ab)c', 'abc')
>>> match[0]
'abc'
>>> match[1]
'ab'
>>> list(match)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '_sre.SRE_Match' object is not iterable

值得注意的是,__iter__方法中没有抛出此异常,因为该方法甚至没有实现:

>>> hasattr(match, '__iter__')
False

那么,如何在不使类可迭代的情况下实现__getitem__

1 个答案:

答案 0 :(得分:51)

有谎言,该死的谎言,然后有Python文档。

对于在 C 中实现的类,拥有__getitem__不足以使其可迭代。这是因为PyTypeObject中实际上有 2 个地方,其中__getitem__可以映射到:tp_as_sequencetp_as_mapping。两者都有一个用于__getitem__[1][2])的插槽。

查看SRE_Match的来源,将tp_as_sequence初始化为NULL,而定义tp_as_mapping

iter()内置函数(如果使用一个参数调用)将调用PyObject_GetIter,它具有以下代码:

f = t->tp_iter;
if (f == NULL) {
    if (PySequence_Check(o))
        return PySeqIter_New(o);
    return type_error("'%.200s' object is not iterable", o);
}

它首先检查tp_iter插槽(显然NULL_SRE_Match个对象);否则,如果 if PySequence_Check返回true,则使用新的序列迭代器,否则引发TypeError

PySequenceCheck首先检查对象是 dict还是dict子类-在这种情况下返回false。否则返回

的值
s->ob_type->tp_as_sequence &&
    s->ob_type->tp_as_sequence->sq_item != NULL;

并且由于s->ob_type->tp_as_sequence实例的NULL_SRE_Match,因此将返回0,并且PyObject_GetIter引发TypeError: '_sre.SRE_Match' object is not iterable