web-dev-qa-db-fra.com

Quand utiliser 'raise NotImplementedError'?

Est-ce à vous rappeler, à vous et à votre équipe, de mettre en œuvre le cours correctement? Je ne comprends pas vraiment l'utilisation d'une classe abstraite comme celle-ci:

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

    def cleanTileAtPosition(self, pos):
        raise NotImplementedError

    def isTileCleaned(self, m, n):
        raise NotImplementedError
49
Antonio Araujo

Comme le dit la documentation [docs] ,

Dans les classes de base définies par l'utilisateur, les méthodes abstraites doivent générer cette exception lorsqu'elles requièrent que des classes dérivées remplacent la méthode ou pendant le développement de la classe pour indiquer que l'implémentation réelle doit encore être ajoutée.

Notez que bien que le principal cas d'utilisation indiqué, cette erreur indique les méthodes abstraites à implémenter sur les classes héritées, vous pouvez l'utiliser comme vous le souhaitez, comme pour l'indication d'un marqueur TODO.

45
Uriel

Comme riel dit , il est destiné à une méthode dans une classe abstraite qui devrait être implémentée dans une classe enfant, mais peut également être utilisé pour indiquer un TODO.

Il existe une alternative pour le premier cas d'utilisation: Classes de base abstraites . Ceux-ci aident à créer des classes abstraites.

Voici un exemple Python 3:

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

Lors de l'instanciation de C, vous obtiendrez une erreur car my_abstract_method est abstrait. Vous devez l'implémenter dans une classe enfant.

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

Sous-classe C et implémenter my_abstract_method.

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

Vous pouvez maintenant instancier D.

C.my_abstract_method ne doit pas nécessairement être vide. Il peut être appelé depuis D en utilisant super().

Un avantage de ceci par rapport à NotImplementedError est que vous obtenez un Exception explicite au moment de l'instanciation, pas au moment de l'appel de la méthode.

19
Jérôme

Considérez si c'était plutôt:

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

    def cleanTileAtPosition(self, pos):
        pass

    def isTileCleaned(self, m, n):
        pass

et vous sous-classez et oubliez de lui dire comment isTileCleaned() ou, peut-être plus probablement, tapez-le comme isTileCLeaned(). Ensuite, dans votre code, vous obtiendrez un None lorsque vous l'appelez.

  • Voulez-vous obtenir la fonction remplacée que vous vouliez? Définitivement pas.
  • La sortie None est-elle valide? Qui sait.
  • Est-ce que le comportement prévu? Presque certainement pas.
  • Voulez-vous obtenir une erreur? Ça dépend.

raise NotImplmentedError vous oblige à le mettre en œuvre, car il lève une exception lorsque vous essayez pour l'exécuter jusqu'à ce que vous le fassiez. Cela supprime beaucoup d'erreurs silencieuses. C'est semblable à pourquoi un sauf que ce n'est jamais une bonne idée : parce que les gens font des erreurs et que cela leur permet de ne pas se perdre.

Remarque: Il est préférable d'utiliser une classe de base abstraite, comme d'autres réponses l'ont mentionné, car les erreurs sont alors chargées à l'avance et le programme ne s'exécute pas tant que vous ne les implémentez pas (avec NotImplementedError, il ne lève une exception que s'il est appelé).

15
TemporalWolf

Vous voudrez peut-être utiliser le décorateur @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
1
Simeon Aleksov