Чтобы напомнить себе и своей команде о правильной реализации класса? Я не могу полностью использовать такой абстрактный класс:
class RectangularRoom(object):
def __init__(self, width, height):
raise NotImplementedError
def cleanTileAtPosition(self, pos):
raise NotImplementedError
def isTileCleaned(self, m, n):
raise NotImplementedError
Ответы:
Как указано в документации [docs] ,
Обратите внимание, что хотя основным заявленным вариантом использования является указание на абстрактные методы, которые должны быть реализованы в унаследованных классах, вы можете использовать ее как угодно, например, для указания
TODO
маркера.источник
abc
(см. Мой ответ ).abstractmethod
и дать поднятьсяNotImplementedError
. Это запрещеноsuper().method()
в реализацияхmethod
в производных классах.Как говорит Уриэль , он предназначен для метода в абстрактном классе, который должен быть реализован в дочернем классе, но может также использоваться для указания 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
во время создания экземпляра, а не во время вызова метода.источник
from abc import ABCMeta, abstractmethod
и определите свою азбуку с помощью__metaclass__ = ABCMeta
. Документы: docs.python.org/2/library/abc.htmlПодумайте, если бы это было:
class RectangularRoom(object): def __init__(self, width, height): pass def cleanTileAtPosition(self, pos): pass def isTileCleaned(self, m, n): pass
и вы создаете подкласс и забываете указать, как это сделать,
isTileCleaned()
или, что более вероятно, опечатайте его какisTileCLeaned()
. Тогда в вашем коде вы получите егоNone
при вызове.None
действительным выход? Кто знает.raise NotImplmentedError
заставляет вас реализовать его, так как он вызовет исключение, когда вы попытаетесь запустить его, пока вы этого не сделаете. Это устраняет множество скрытых ошибок. Это похоже на то, почему голое исключение почти никогда не бывает хорошей идеей : потому что люди делают ошибки, и это гарантирует, что их не заметят под ковриком.Примечание.Использование абстрактного базового класса, как упоминалось в других ответах, еще лучше, поскольку тогда ошибки загружаются заранее, и программа не будет запускаться, пока вы их не реализуете (с NotImplementedError он будет генерировать исключение только в случае фактического вызова).
источник
Можно также сделать
raise NotImplementedError()
внутри дочернего метода метода@abstractmethod
базового класса с декорированием.Представьте, что вы пишете сценарий управления для семейства измерительных модулей (физических устройств). Функциональность каждого модуля четко определена и реализует только одну специализированную функцию: одно может быть массивом реле, другое - многоканальным ЦАП или АЦП, третьим - амперметром и т. Д.
Многие из используемых низкоуровневых команд будут совместно использоваться модулями, например, для чтения их идентификационных номеров или для отправки им команды. Посмотрим, что у нас есть на данный момент:
Базовый класс
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 modules
Общие глаголы
Затем мы понимаем, что большая часть командных глаголов модуля и, следовательно, логика их интерфейсов также являются общими. Вот 3 разных глагола, значение которых не требует пояснений, учитывая количество целевых модулей.
get(channel)
реле: включить / выключить состояние реле
channel
ЦАП: включите выходное напряжение
channel
АЦП: включите входное напряжение
channel
enable(channel)
реле: включить использование реле на
channel
ЦАП: включить использование выходного канала на
channel
ADC: разрешить использование входного канала на
channel
set(channel)
реле: включить
channel
/ выключить релеЦАП: установите выходное напряжение на
channel
ADC: хм ... ничего логичного в голову не приходит.
Общие глаголы становятся принудительными глаголами
Я бы сказал, что есть веские основания для использования вышеуказанных глаголов в модулях, поскольку мы видели, что их значение очевидно для каждого из них. Я бы продолжил писать свой базовый класс
Generic
так:class Generic(ABC): # ...continued @abstractmethod def get(self, channel): pass @abstractmethod def enable(self, channel): pass @abstractmethod def set(self, channel): pass
Подклассы
Теперь мы знаем, что все наши подклассы должны будут определять эти методы. Посмотрим, как это может выглядеть для модуля 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'
Теперь вам может быть интересно:
Вы правы: отказ от реализации
set
- это не вариант, так как Python тогда вызовет ошибку ниже, когда вы попытаетесь создать экземпляр своего объекта ADC.TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'
Таким образом , вы должны реализовать что - то, потому что мы сделали исполнение глагола ( так называемый «@abstractmethod»), который является общим для двух других модулей , но в то же время, вы также не должны ничего как реализовать
set
set
не имеет смысла для данного конкретного модуля.NotImplementedError спешит на помощь
Заполнив класс ADC следующим образом:
class ADC(Generic): # ...continued def set(self, channel): raise NotImplementedError("Can't use 'set' on an ADC!")
Вы делаете сразу три очень хороших дела:
источник
Возможно, вы захотите использовать
@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
источник