Почему и когда операторы литерального сравнения, такие как `==` в Python, используют встроенный метод magi c пользовательского типа? - PullRequest
1 голос
/ 04 февраля 2020

Страница docs.python.org в Python «Модель данных» сообщает , что когда обе стороны в операции буквального сравнения реализуют магические c методы для операции, метод левый операнд используется с правым операндом в качестве аргумента:

x<y вызовов x.__lt__(y), x<=y вызовов x.__le__(y), x==y вызовов x.__eq__(y), x!=y звонки x.__ne__(y), x>y звонки x.__gt__(y) и x>=y звонки x.__ge__(y).

Следующий класс охватывает builtin tuple и реализует маги c метод для одного из этих операторов сравнения, чтобы продемонстрировать это:

class eqtest(tuple):
 def __eq__(self, other):
  print('Equivalence!')

При использовании экземпляров этого класса в левой части оператора сравнения он ведет себя как ожидалось:

>>> eqtest((1,2,3)) == (1,2,3)
Equivalence!

Однако оператор сравнения пользовательского класса, кажется, вызывается даже при использовании только его экземпляра справа:

>>> (1,2,3) == eqtest((1,2,3))
Equivalence!

Результат также заметно отличается, когда метод magi c левого операнда явно называется:

>>> (1,2,3).__eq__(eqtest2((1,2,3)))
True

Это легко понять и почему это может быть преднамеренным выбором дизайна, особенно с подклассами, для возврата результата, который, скорее всего, будет полезен из типа, который был определен позже. Однако, поскольку он довольно явно отклоняется от базового c документированного поведения, довольно трудно понять, как и почему он работает таким образом, достаточно уверенно, чтобы учесть и использовать его в производстве.

В чем В случаях, когда язык Python и эталонная реализация CPython меняют порядок операторов сравнения, даже если обе стороны предоставляют действительные результаты, и где это задокументировано?

1 Ответ

2 голосов
/ 04 февраля 2020

Правила сравнения гласят, что кортежи не знают, как сравнивать с другими типами. tuplerichcompare делает Py_RETURN_NOTIMPLEMENTED. Однако PyObject richcompare проверяет подтипы, такие как унаследованный класс, и меняет порядок сравнения (применяя правило симметрии).

Это также задокументировано на странице, на которую вы ссылаетесь:

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

Это позволяет подклассам реализовывать более специфичные c поведения, которые работают со сравнением, записанным в любом случае.

...