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.
Ответы
Ответ 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__
.