繁体   English   中英

是否强制执行抽象方法实现 unpythonic?

[英]Is enforcing an abstract method implementation unpythonic?

在设计类时,抽象方法非常有用。 据我所知,Python 没有强制继承的 class 实现抽象方法的机制。 在我的代码中(参见下面的示例),我在基础 class 中输入了一个失败的断言,如果未实现会导致运行时错误。 这是非pythonic吗?

class Dog(Animal):
  def speak(self):
   return "bark"

class Animal():
  def speak(self):
   assert(False) #abstract

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
>>> 

另一方面, “这是pythonic”的基本问题有点难说。 如果您的意图是提供抽象基础 class 以便您以后可以检查以确保值从它继承,那么不,这不是特别pythonic,即使可以使任意类型抽象基类的子类。 另一方面,提供一个基于具体子类中提供的实现来实现某些功能的抽象基类是非常好的。 例如, collections.Sequencecollections.Mapping对 list like 和 dict like classes 执行此操作; 子类可以提供__getitem__并且可以免费获得__contains__等。

当然,你不应该使用assert()除了记录代码的期望; 如果断言实际上有可能失败,则不应使用断言。 优化 python ( 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 您可能希望这样做,因为您确实需要该 class 的实例,其中一些可能不需要实现可选功能。 您仍然应该考虑通过super()调用 function 的可能性。 大致上,这可能看起来像这样。

class Foo(object):
    def bar(self, baz):
        if self.bar.im_func == Foo.bar.im_func:
            raise NotImplementedError, "Subclasses must implement bar"

ABC 是 C++ 的产物,与鸭式打字相反。 如果 class Animal 没有定义speak它会毫不费力地做你想做的事。

>>> class Animal(object):
...     pass
... 
>>> class Dog(Animal):
...     def speak(self):
...             print "bark"
... 
>>> animal = Animal()
>>> dog = Dog()
>>> animal.speak()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Animal' object has no attribute 'speak'
>>> dog.speak()
bark

C++ 和相关语言强制你创建 ABC,因为 ABC 实际上是一个接口描述。 Python 避开了编译器强制接口声明,因为它们试图用代码记录通过语言外方式更好地执行的合同。

好吧,如果你没有在你的基础 class 中包含方法speak并且以某种方式碰巧使用它,那么代码无论如何都会失败。 问题是,它的可能性有多大以及如何告诉用户( NotImplementedError在这里可能比断言更适合)。

通常,使用 python 并不总是可以直接对代码实施限制,至少从面向 object 的角度来看(考虑抽象类、私有方法……)。 要强制子类实现方法,您可能需要执行以下操作:

class Animal():
  def speak(self):
   raise NotImplementedError #abstract

class Dog(Animal):
  def speak(self):
   return "bark"

class MuteAnimal(Animal):
  pass

这并不意味着该方法将由子类实现,但它只会在未实现 speak 方法时引发错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM