Как работает функция Python reversed ()? - PullRequest
0 голосов
/ 05 июля 2018

Согласно Документам Python , reversed() использует __getitem__ и __len__, если __reversed__ не реализовано.

Я столкнулся со странным поведением и не смог его объяснить:

>>> class A(dict):
...     pass
...
>>> reversed(A())
Traceback (most recent call last):
    ...
TypeError: 'A' object is not reversible

>>> class B(dict):
...     def __getitem__(self, key):
...         return super().__getitem__(key)
...     def __len__(self):
...         return super().__len__()
...
>>> reversed(B())
Traceback (most recent call last):
    ...
TypeError: 'B' object is not reversible

>>> class C:
...     def __getitem__(self, key):
...         return "item"
...     def __len__(self):
...         return 1
...
>>> reversed(C())
<reversed object at 0x00000000022BB9B0>

Хотя вызов reversed() для типов отображения не имеет смысла, откуда он знает, что это отображение? Внутренне проверяет isinstance(inst, dict)? Проверяет ли оно какое-либо общее отображение типа collections.abc.Mapping? Есть ли способ переопределить это поведение без реализации __reversed__?

Я думал, что это может быть связано с тем, что dict реализует __reversed__, который выбрасывает TypeError, или тот, который равен None, очень похоже на то, как вы отключаете __hash__, но dict.__reversed__ оказалось пустым с AttributeError брошено.

1 Ответ

0 голосов
/ 05 июля 2018

Да, есть проверка для dict типа PySequence_Check , используемого reversed.

// cpython/Objects/enumobject.c
if (!PySequence_Check(seq)) {
    PyErr_Format(PyExc_TypeError,
                 "'%.200s' object is not reversible",
                 Py_TYPE(seq)->tp_name);
    return NULL;
}


// cpython/Objects/abstract.c

int
PySequence_Check(PyObject *s)
{
    if (PyDict_Check(s))
        return 0;
    return s != NULL && s->ob_type->tp_as_sequence &&
        s->ob_type->tp_as_sequence->sq_item != NULL;
}
...