Почему объекты regex match не являются итерационными, даже если они реализуют getitem?
как вы знаете, осуществляет __getitem__
метод делает класс 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
, это не справедливо для объектов regex матч:
>>> 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__
без создания класса iterable?
1 ответов
есть ложь, проклятая ложь, а затем есть документация Python.
С __getitem__
для класса, реализованного в C недостаточно для итерации. Это потому, что на самом деле 2 мест в PyTypeObject
здесь __getitem__
можно сопоставить с:tp_as_sequence
и tp_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
объекты); и в противном случае, тогда если PySequence_Check
возвращает true, новый итератор последовательности, else a TypeError
is поднятый.
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
.