Python на самом деле имеет абстрактные классы с абстрактными методами:
>>> import abc
>>>
>>> class IFoo(object):
... __metaclass__ = abc.ABCMeta
...
... @abc.abstractmethod
... def foo(self):
... pass
...
>>> foo = IFoo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cant instantiate abstract class IFoo with abstract methods foo
>>> class FooDerived(IFoo):
... pass
...
>>> foo = FooDerived()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cant instantiate abstract class FooDerived with abstract methods foo
>>> class FooImplements(FooDerived):
... def foo(self):
... print "foo'ed"
...
>>> foo = FooImplements()
>>> foo.foo()
foo'ed
>>>
С другой стороны, фундаментальный вопрос "Является ли этот питон" немного сложнее сказать.Если ваше намерение состоит в том, чтобы предоставить абстрактный базовый класс, чтобы позже вы могли проверить, что значения наследуют от него, то нет, это не особенно питонно, даже если можно сделать произвольные типы абстрактными подклассами вашего базового класса.С другой стороны, совершенно нормально предоставить абстрактный базовый класс, который реализует некоторые функциональные возможности на основе реализации, предоставленной в конкретных подклассах.Например, collections.Sequence
и collections.Mapping
делают это только для классов, подобных спискам, и классов, подобных диктовкам;подклассы могут предоставить __getitem__
и могут получить __contains__
и другие бесплатно.
Наверняка вам никогда не следует использовать assert()
, кроме как для документирования ожиданий кода;Если на самом деле возможен сбой утверждения, вам не следует использовать утверждение.Оптимизированный питон (python -O script.py
) не проверяет утверждения.
Редактировать: дополнительная экспозиция:
Если вы проверяете тип значения:
def foo(bar):
if not isinstance(bar, AbstractBaz):
raise ValueError, ("bar must be an instance of AbstractBaz, "
"got %s" % type(bar))
Если по какой-то причине вы не можете использовать @abstractmethod
, новсе еще хотите этот эффект, вы должны поднять NotImplementedError
.Возможно, вы захотите сделать это, потому что вам действительно нужны экземпляры этого класса, некоторые из которых могут не нуждаться в реализации дополнительных функций.Вы все еще должны учитывать возможность того, что функция была вызвана через super()
.В первом приближении это может выглядеть следующим образом.
class Foo(object):
def bar(self, baz):
if self.bar.im_func == Foo.bar.im_func:
raise NotImplementedError, "Subclasses must implement bar"