Подтвердить что ты не робот

Python NotImplemented constant

Просматривая decimal.py, он использует NotImplemented во многих специальных методах. например.

class A(object):
    def __lt__(self, a):
        return NotImplemented

    def __add__(self, a):
        return NotImplemented

Документы Python говорят:

NotImplemented

Специальное значение, которое может быть возвращено "богатым сравнением" специальные методы (__eq__(), __lt__(), и друзей), чтобы указать, что сравнение не выполняется с по отношению к другому типу.

Он не говорит о других специальных методах и не описывает поведение.

Кажется, что это волшебный объект, который, если он возвращается из других специальных методов, поднимает TypeError, а в "богатом сравнении" специальные методы ничего не делают.

например.

print A() < A()

выводит True, но

print A() + 1

вызывает TypeError, поэтому мне интересно, что происходит и каково использование/поведение NotImplemented.

4b9b3361

Ответ 1

NotImplemented позволяет указать, что сравнение между двумя заданными операндами не реализовано (вместо того, чтобы указывать, что сравнение действительно, но дает False для двух операндов).

Из Справочник по языку Python:

Для объектов x и y сначала x.__op__(y)судится. Если это не реализовано или возвращает NotImplemented, y.__rop__(x). Если это также не реализован или не возвращается NotImplemented, исключение TypeError Поднялся. Но см. Следующие исключение:

Исключение к предыдущему item: если левый операнд экземпляр встроенного типа или класс нового стиля и правый операнд является экземпляром соответствующего подкласса этот тип или класс и переопределяет базовый метод __rop__(), правый метод операнда __rop__()перед левым операндом __op__()метод. Это делается для того, чтобы подкласс может полностью переопределить бинарных операторов. В противном случае, слева операнд __op__() всегда будет принять правильный операнд: когда экземпляр данного класса ожидается, экземпляр подкласса этого класс всегда приемлем.

Ответ 2

На самом деле это имеет тот же смысл, когда возвращается с __add__ как из __lt__, разница заключается в том, что Python 2.x пытается использовать другие способы сравнения объектов перед __lt__. Python 3.x создает TypeError. На самом деле Python может попробовать другие вещи для __add__ а также взглянуть на __radd__ и (хотя я __coerce__ на нем) __coerce__.

# 2.6
>>> class A(object):
...   def __lt__(self, other):
...     return NotImplemented
>>> A() < A()
True

# 3.1
>>> class A(object):
...   def __lt__(self, other):
...     return NotImplemented
>>> A() < A()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: A() < A()

Подробнее см. В разделе " Сравнение заказов" (3.0 docs).

Ответ 3

Если вы вернете его из __add__, он будет вести себя так, как будто объект не имеет метода __add__, и поднимите TypeError.

Если вы возвращаете NotImplemented из богатой функции сравнения, Python будет вести себя так же, как метод не был реализован, то есть он отложит использование __cmp__.