为什么正则表达式匹配对象即使实现__getitem__也不可迭代?

Ara*_*Fey 53 python iterable

您可能知道,实现__getitem__方法会使类可迭代:

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
Run Code Online (Sandbox Code Playgroud)

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

>>> 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
Run Code Online (Sandbox Code Playgroud)

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

>>> hasattr(match, '__iter__')
False
Run Code Online (Sandbox Code Playgroud)

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

Ant*_*ala 53

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

拥有__getitem__C实现的类是不够的可迭代.那是因为在可以映射到的地方实际上有2个位置:和.两者都有([1],[2])的插槽.PyTypeObject__getitem__tp_as_sequencetp_as_mapping__getitem__

查看源的SRE_Match,tp_as_sequence初始化为NULLwhile 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);
}
Run Code Online (Sandbox Code Playgroud)

它首先检查tp_iter插槽(显然NULL_SRE_Match对象); 如果 失败,那么如果PySequence_Check返回true,返回一个新的序列迭代器,否则TypeError引发a.

PySequenceCheck首先检查是否该对象是一个dict或一个dict子类 -在此情况下,返回false.否则返回值

s->ob_type->tp_as_sequence &&
    s->ob_type->tp_as_sequence->sq_item != NULL;
Run Code Online (Sandbox Code Playgroud)

因为s->ob_type->tp_as_sequenceNULL一个_SRE_Match实例,将返回0,并PyObject_GetIter加注TypeError: '_sre.SRE_Match' object is not iterable.