¿Es para recordarse a sí mismo y a su equipo que deben implementar la clase correctamente? No consigo el uso completo de una clase abstracta como esta:
class RectangularRoom(object):
def __init__(self, width, height):
raise NotImplementedError
def cleanTileAtPosition(self, pos):
raise NotImplementedError
def isTileCleaned(self, m, n):
raise NotImplementedError

Respuestas:
Como dice la documentación [docs] ,
Tenga en cuenta que, aunque el caso de uso principal declarado, este error es la indicación de métodos abstractos que deben implementarse en clases heredadas, puede usarlo de la forma que desee, como para indicar un
TODOmarcador.fuente
abc(ver mi respuesta ).abstractmethody deja que subaNotImplementedError. Esto prohíbesuper().method()en implementaciones demethodclases derivadas.Como dice Uriel , está destinado a un método en una clase abstracta que debe implementarse en la clase secundaria, pero que también se puede usar para indicar un TODO.
Existe una alternativa para el primer caso de uso: clases base abstractas . Aquellos ayudan a crear clases abstractas.
Aquí hay un ejemplo de Python 3:
class C(abc.ABC): @abstractmethod def my_abstract_method(self, ...): ...Al crear una instancia
C, obtendrá un error porquemy_abstract_methodes abstracto. Necesitas implementarlo en una clase secundaria.TypeError: Can't instantiate abstract class C with abstract methods my_abstract_methodSubclase
Ce implementomy_abstract_method.class D(C): def my_abstract_method(self, ...): ...Ahora puedes crear una instancia
D.C.my_abstract_methodno tiene que estar vacío. Se puede llamarDusandosuper().Una ventaja de esto
NotImplementedErrores que obtiene un explícitoExceptionen el momento de la instanciación, no en el momento de la llamada al método.fuente
from abc import ABCMeta, abstractmethody define tu ABC con__metaclass__ = ABCMeta. Documentos: docs.python.org/2/library/abc.htmlConsidere si en cambio fue:
class RectangularRoom(object): def __init__(self, width, height): pass def cleanTileAtPosition(self, pos): pass def isTileCleaned(self, m, n): passy usted subclasifica y se olvida de decirle cómo
isTileCleaned()o, quizás más probablemente, escribe comoisTileCLeaned(). Luego, en su código, obtendrá unNonecuando lo llame.Noneuna salida válida? Quién sabe.raise NotImplmentedErrorfuerzas que ponerlo en práctica, ya que será una excepción cuando intenta ejecutar hasta que lo haga. Esto elimina muchos errores silenciosos. Es similar a la razón por la que una excepción desnuda casi nunca es una buena idea : porque la gente comete errores y esto asegura que no se barren debajo de la alfombra.Nota: Usar una clase base abstracta, como han mencionado otras respuestas, es mejor aún, ya que entonces los errores se cargan por adelantado y el programa no se ejecutará hasta que los implemente (con NotImplementedError, solo lanzará una excepción si realmente se llama).
fuente
También se podría hacer un método
raise NotImplementedError()dentro del hijo de un método de@abstractmethodclase base decorado.Imagine escribir un script de control para una familia de módulos de medición (dispositivos físicos). La funcionalidad de cada módulo se define de manera estricta, implementando solo una función dedicada: una podría ser una matriz de relés, otra un DAC o ADC multicanal, otra un amperímetro, etc.
Gran parte de los comandos de bajo nivel en uso se compartirían entre los módulos, por ejemplo, para leer sus números de identificación o enviarles un comando. Veamos qué tenemos en este punto:
Clase base
from abc import ABC, abstractmethod #< we'll make use of these later class Generic(ABC): ''' Base class for all measurement modules. ''' # Shared functions def __init__(self): # do what you must... def _read_ID(self): # same for all the modules def _send_command(self, value): # same for all the modulesVerbos compartidos
Entonces nos damos cuenta de que gran parte de los verbos de comando específicos del módulo y, por lo tanto, la lógica de sus interfaces también se comparte. Aquí hay 3 verbos diferentes cuyo significado se explica por sí mismo considerando una serie de módulos de destino.
get(channel)relé: activa el estado de encendido / apagado del relé
channelDAC: activa el voltaje de salida
channelADC: activa el voltaje de entrada
channelenable(channel)relé: habilita el uso del relé en
channelDAC: habilita el uso del canal de salida en
channelADC: habilita el uso del canal de entrada en
channelset(channel)relé: enciende
channel/ apaga el reléDAC: configure el voltaje de salida en
channelADC: hmm ... no se me ocurre nada lógico .
Los verbos compartidos se convierten en verbos obligatorios
Yo diría que hay un caso sólido para que los verbos anteriores se compartan entre los módulos, ya que vimos que su significado es evidente para cada uno de ellos. Continuaría escribiendo mi clase base
Genericasí:class Generic(ABC): # ...continued @abstractmethod def get(self, channel): pass @abstractmethod def enable(self, channel): pass @abstractmethod def set(self, channel): passSubclases
Ahora sabemos que todas nuestras subclases tendrán que definir estos métodos. Veamos cómo se vería para el módulo ADC:
class ADC(Generic): def __init__(self): super().__init__() #< applies to all modules # more init code specific to the ADC module def get(self, channel): # returns the input voltage measured on the given 'channel' def enable(self, channel): # enables accessing the given 'channel'Puede que ahora te estés preguntando:
Tienes razón: no implementar no
setes una opción, ya que Python dispararía el siguiente error cuando intentas crear una instancia de tu objeto ADC.TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'Entonces debes implementar algo, porque creamos
setun verbo forzado (también conocido como '@abstractmethod'), que es compartido por otros dos módulos pero, al mismo tiempo, tampoco debes implementar nada, yasetque no tiene sentido para este módulo en particular.NotImplementedError al rescate
Al completar la clase ADC de esta manera:
class ADC(Generic): # ...continued def set(self, channel): raise NotImplementedError("Can't use 'set' on an ADC!")Estás haciendo tres cosas muy buenas a la vez:
fuente
Es posible que desee utilizar el
@propertydecorador,>>> 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 implementedfuente