Python抽象基类可以强制执行函数签名吗?

时间:2014-08-07 13:09:16

标签: python abstract-base-class

假设我像这样定义abstract base class

from abc import abstractmethod, ABCMeta

class Quacker(object):
  __metaclass__ = ABCMeta

  @abstractmethod
  def quack(self):
    return "Quack!"

这可确保从Quacker派生的任何类都必须实现quack方法。但是,如果我定义以下内容:

class PoliteDuck(Quacker):
   def quack(self, name):
     return "Quack quack %s!" % name

d = PoliteDuck()  # no error

我允许实例化该课程,因为我提供了quack方法,但功能签名并不匹配。我可以看到这在某些情况下可能有用,但我有兴趣确保我可以肯定地调用抽象方法。如果函数签名不同,这可能会失败!

那么:我如何强制执行匹配的函数签名?如果签名不匹配,我希望在创建对象时出错,就像我没有定义一样它根本就没有。

知道这不是惯用的,如果我想要这些类型的保证,Python就是错误的语言,但旁边的那个关键 - 有可能吗?

2 个答案:

答案 0 :(得分:21)

这比你想象的要糟糕。抽象方法仅按名称进行跟踪,因此您甚至不必将quack作为方法来实例化子类。

class SurrealDuck(Quacker):
    quack = 3

d = SurrealDuck()
print d.quack   # Shows 3

系统中没有任何内容强制quack甚至是一个可调用的对象,更不用说其参数与抽象方法的原始对象相匹配的对象了。最好的情况是,您可以创建子类ABCMeta并自己添加代码,以将子代码中的类型签名与父代中的原始代码进行比较,但这实现起来并不重要。

(目前,将某些内容标记为“abstract”实质上只是将名称添加到父级(Quacker.__abstractmethods__)中的冻结集属性中。使类可实例化就像将此属性设置为空迭代一样简单,对测试很有用。)

答案 1 :(得分:6)

我建议你看看pylint。我通过它的静态分析运行了这段代码,在你定义quack()方法的行上,它报告了:

Argument number differs from overridden method (arguments-differ)

https://en.wikipedia.org/wiki/Pylint