您可能知道,实现__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_sequence
tp_as_mapping
__getitem__
查看源的SRE_Match
,tp_as_sequence
初始化为NULL
while 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_sequence
是NULL
一个_SRE_Match
实例,将返回0,并PyObject_GetIter
加注TypeError: '_sre.SRE_Match' object is not iterable
.