首页 > 解决方案 > 为什么正则表达式匹配对象即使实现了__getitem__也不能迭代?

问题描述

您可能知道,实现__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

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

>>> 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__不使类可迭代的情况下实现呢?

标签: pythoniterable

解决方案


有谎言,该死的谎言,还有 Python 文档。

拥有一个用C__getitem__实现的类还不足以让它成为可迭代的。那是因为实际上有2地方可以映射到:和. 两者都有一个用于([1][2])的插槽。PyTypeObject__getitem__tp_as_sequencetp_as_mapping__getitem__

查看 , 的来源SRE_Matchtp_as_sequence被初始化为,NULLtp_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对象);如果失败,则如果 PySequence_Check返回 true,则生成一个新的序列迭代器,否则TypeError引发 a。

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

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

并且因为s->ob_type->tp_as_sequenceNULL例如_SRE_Match, 0 将被返回,并PyObject_GetIterraises TypeError: '_sre.SRE_Match' object is not iterable


推荐阅读