Зачем возвращать NotImplemented вместо повышения NotImplementedError

283

У Python есть синглтон NotImplemented.

Почему кто-то хотел бы когда-нибудь вернуться NotImplementedвместо того, чтобы поднять NotImplementedErrorисключение? Разве это не затруднит поиск ошибок, таких как код, выполняющий недопустимые методы?

abyx
источник

Ответы:

281

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

http://jcalderone.livejournal.com/32837.html

Подводя итог этой ссылке:

" NotImplementedсигнализирует среде выполнения, что он должен попросить кого-то другого выполнить операцию. В выражении a == b, если a.__eq__(b)возвращается NotImplemented, то Python пытается b.__eq__(a). Если bзнает достаточно для возврата Trueили False, тогда выражение может завершиться успешно. Если это не так, тогда среда выполнения будет отступить к встроенному поведению (которое основано на идентичности для ==и !=). "

косяк
источник
5
Я был бы осторожен, используя его, так как эта ссылка указывает в конце документа.
Джейсон Кун
16
Когда интерпретатор Python проверяет, a.__eq__(b)возвращен ли NotImplemented, не может ли он так же легко перехватить NotImplementedError вместо этого (и затем вызвать b.__eq__(a)или что-то еще)?
Veky
24
@Veky. Повышение исключения, вероятно, имеет более высокие издержки. Любые накладные расходы в операции сортировки будут увеличены на размер списка, поэтому, даже если разница будет очень маленькой, все равно будет иметь смысл найти более быструю реализацию. Вы также не хотите прерывать свои циклы и повторно вводить их, что потребует реализация try / catch.
SpliFF
3
Во-первых, еще более быстрым решением было бы автоматически синтезировать lt как обращенный gt, вместо того, чтобы всегда вызывать что-то, что будет возвращать NotImplemented - а Python этого не делает. Я не думаю, что здесь причина в скорости. И, во-вторых, я не понимаю, что вы говорите: для возврата потребуется столько же разрывов циклов, сколько и для рейза. Фактически вы можете представить return как выдачу специального исключения Return, которое всегда попадает в область вызова.
Veky
2
>> "увеличено на размер списка" По крайней мере, если у вас нет типа O (n), о котором мир должен знать.
Джонатан Хартли
107

Потому что у них разные варианты использования.

Цитирование документов (Python 3.6):

Не реализована

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

исключение NotImplementedError

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

Смотрите ссылки для деталей.

Paolo
источник
Это должен быть принятый ответ. Это даже сильнее, чем варианты использования, это указание на намерение - тот, у которого ошибка в конце имени, сигнализирует о том, что произошла ошибка (потому что что-то не реализовано), другой не ошибка, а «правильный» поведение. Я бы сравнил это с разницей между возвратом NaN или поднятием ValueError.
Короне
13

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

RichieHindle
источник