Почему при вызове __reversed__ в кортеже возникает ошибка атрибута? - PullRequest
0 голосов
/ 01 мая 2020

Как я понимаю, метод волхва c объекта можно вызвать любым из двух способов. Во-первых, вот так, где метод magi c вызывается как любой обычный метод:

x = (1, 2, 3, 4)
print(x.__len__())
#prints 4

И, во-вторых, вот так, где метод magi c называется «специально»:

x = (1, 2, 3, 4)
print((len(x)))
#prints 4

Как мы видим, оба эквивалентны. Однако, когда я вызываю метод magi c reversed() для кортежа с первым способом, я сталкиваюсь с ошибкой:

x = (1, 2, 3, 4)
x.__reversed__()
#causes an attribute error

Однако «специальный» способ вызова обращенного метода работает прекрасно:

x = (1, 2, 3, 4)
reversed(x)
#returns a reversed object

Почему это происходит? Неужели я что-то не так понял о более сложных методах?

Ответы [ 3 ]

7 голосов
/ 01 мая 2020

Большинство маги c методов не эквивалентны тому, что они выглядят, как они должны быть эквивалентны. __add__ не эквивалентно +. __iadd__ не эквивалентно +=. __iter__ не эквивалентно iter. Ни __getattribute__, ни __getattr__ не эквивалентны getattr (или обычному доступу к атрибутам).

В продолжение шаблона __reversed__ не эквивалентно reversed. Если reversed найдет метод __reversed__, он будет использовать этот метод, но если нет, он просто создаст итератор, который получает доступ к аргументу спереди назад с помощью обычной индексации. Последовательность не нуждается в методе __reversed__, а tuple не имеет метода.

2 голосов
/ 01 мая 2020

Ваше предположение, что должен быть метод __reversed__, неверно:

reversed(seq)

Вернуть обратный итератор. seq должен быть объектом, у которого есть метод __reversed __ () или , поддерживающий протокол последовательности ( метод __len __ () и метод __getitem __ () с целочисленными аргументами, начинающимися с 0 ).

1 голос
/ 01 мая 2020

Поскольку reversed выполняет одно из следующих действий в зависимости от аргумента:

  1. Аргумент - это объект с __reversed__ magi c методом, а reversed просто вызывает его и возвращает данный итератор .
>>> class A:
...     def __reversed__(self):
...         yield 17
...         yield 42
>>> a = A()
>>> reversed(a)
<generator object A.__reversed__ at 0x7fa1283e8e40>
>>> list(reversed(a))
[17, 42]
Аргумент - это последовательность (например, tuple или str), которая имеет __len__ и __getitem__, а __reversed__ создает промежуточный объект, который возвращает элементы последовательности от последнего к первому.
>>> t = (42, 17)
>>> reversed(t)
<reversed object at 0x7fa12840fc40>
>>> list(reversed(t))
[17, 42]

Из документов

reversed(seq) Вернуть обратный итератор. seq должен быть объектом, который имеет метод __reversed__() или поддерживает протокол последовательности (метод __len__() и метод __getitem__() с целочисленными аргументами, начинающимися с `0).

Подробнее как правило, вам, вероятно, не следует вызывать более сложные методы (поскольку это очень опасный способ, особенно в производственном коде) и использовать специальные функции / классы для доступа к ним, например reversed / len.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...