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

Mik*_*ike 6 python oop

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

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

class Animal():
  def speak(self):
   assert(False) #abstract
Run Code Online (Sandbox Code Playgroud)

Sin*_*ion 12

蟒蛇其实确实有抽象类与abstact方法:

>>> 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
>>> 
Run Code Online (Sandbox Code Playgroud)

另一方面,"这个pythonic"的基本问题有点难以说.如果你的目的是提供抽象基类,以便稍后检查以确保值继承它,那么不,这不是特别pythonic,即使可以使任意类型抽象基类的子类.另一方面,提供一个基于具体子类中提供的实现实现某些功能的抽象基类是完美的.例如,collections.Sequence并且collections.Mapping只做这对于像列表和字典一样班; 子类可以提供__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))
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因你不能使用@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"
Run Code Online (Sandbox Code Playgroud)


msw*_*msw 5

ABCs是C++的工件,与鸭子打字相反.如果动物类没有定义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
Run Code Online (Sandbox Code Playgroud)

C++和相关语言迫使您创建ABC,因为ABC实际上是一个接口描述.Python避免编译器强制执行的接口声明,因为它们试图在代码中记录通过语言外方法更好地执行的合同.

  • 此外,如果您要求库的用户实现一种在课堂上混合的方法,那么ABCs和/或抽象方法在鸭子打字领域是完全有效的.如果它是适当的软件工程,谁会关心它是否是"unpythonic"还是与特定社区的灌输信念背道而驰.看看下面的TokenMacGuy的答案并忽略这个人. (7认同)
  • "Python避免了编译器强制执行的接口声明,因为它们试图在代码中记录一个通过语言外手段更好地执行的合同." WTF?请澄清这一说法,它可能会使其对其他人更有帮助. (3认同)