Когда использовать 'raise NotImplementedError'?

Следует ли помнить себя и свою команду, чтобы правильно реализовать класс? Я не полностью использую абстрактный класс следующим образом:

class RectangularRoom(object):
    def __init__(self, width, height):
        raise NotImplementedError

    def cleanTileAtPosition(self, pos):
        raise NotImplementedError

    def isTileCleaned(self, m, n):
        raise NotImplementedError

Ответ 1

Как говорится в документации [docs],

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

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

Ответ 2

Как Уриэль говорит, он предназначен для метода в абстрактном классе, который должен быть реализован в дочернем классе, но может использоваться для обозначения TODO.

Python 3 поставляется с альтернативой для первого варианта использования: Абстрактные базовые классы. Это помогает создавать абстрактные классы:

class C(abc.ABC):
    @abstractmethod
    def my_abstract_method(self, ...):
    ...

При создании экземпляра C вы получите сообщение об ошибке, потому что my_abstract_method является абстрактным. Вам нужно реализовать его в дочернем классе.

TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method

Подкласс C и реализовать my_abstract_method.

class D(C):
    def my_abstract_method(self, ...):
    ...

Теперь вы можете создать экземпляр D.

C.my_abstract_method не должно быть пустым. Его можно вызвать из D с помощью super().

Преимущество этого над NotImplementedError заключается в том, что вы получаете явное Exception во время создания, а не во время вызова метода.

Ответ 3

Возможно, вы захотите использовать декоратор @property,

>>> class Foo():
...     @property
...     def todo(self):
...             raise NotImplementedError("To be implemented")
... 
>>> f = Foo()
>>> f.todo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in todo
NotImplementedError: To be implemented

Ответ 4

Рассмотрим, если бы это было:

class RectangularRoom(object):
    def __init__(self, width, height):
        pass

    def cleanTileAtPosition(self, pos):
        pass

    def isTileCleaned(self, m, n):
        pass

и вы подклассом и забудьте сообщить ему, как isTileCleaned() или, возможно, более вероятно, оставьте его как isTileCleaned(). Затем в вашем коде вы получите None, когда вы его вызовете.

  • Вы получите переопределенную функцию, которую хотите? Определенно нет.
  • Является ли None допустимым выходом? Кто знает.
  • Это намеренное поведение? Почти наверняка нет.
  • Вы получите сообщение об ошибке? Это зависит.

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