【问题标题】:Abstract methods with specific arguments in PythonPython中具有特定参数的抽象方法
【发布时间】:2014-03-22 18:49:20
【问题描述】:

我用 abc 包实现抽象类。下面的程序显示没有问题。

有什么办法让它失败,因为抽象MyMethod 确实有一个参数a,但在类Derivative 中实现'MyMethod' 没有?所以我不仅要指定接口类Base中的方法,还要指定这些方法的参数。

import abc

#Abstract class
class Base(object):
    __metaclass__  = abc.ABCMeta

    @abc.abstractmethod
    def MyMethod(self, a):
        'MyMethod prints a'


class Derivative(Base)

    def MyMethod(self):
        print 'MyMethod'

【问题讨论】:

  • 不,abc.abstractmethod 不强制必须存在哪些参数。
  • Martijn,还有其他方法可以强制执行参数吗?可能与 abc 不同。
  • zope.interface 可以verify method signatures。但是你需要明确地这样做(比如在单元测试中)。
  • 您的项目是否复杂到需要这种静态检查?如果是,Python 可能不是您的最佳语言选择。
  • Sven,我正在实施的是一个用于网络设备黑盒测试的系统。我使用抽象类在我的软件的 HAL 层中为各种 CLI/SNMP 指定接口(除了硬件适配层之外,各种设备的测试看起来都一样)。 Python 编写测试非常方便。

标签: python class oop abstract abc


【解决方案1】:

下面的代码是从代理类复制的,其工作方式类似。它检查所有方法是否存在以及方法签名是否相同。这项工作在 _checkImplementation() 中完成。注意以 ourf 和 theirf 开头的两行; _getMethodDeclaration() 将签名转换为字符串。这里我选择要求两者完全相同:

  @classmethod
  def _isDelegatableIdentifier(cls, methodName):
    return not (methodName.startswith('_') or methodName.startswith('proxy'))



  @classmethod
  def _getMethods(cls, aClass):
    names  = sorted(dir(aClass), key=str.lower)
    attrs  = [(n, getattr(aClass, n)) for n in names if cls._isDelegatableIdentifier(n)]
    return dict((n, a) for n, a in attrs if inspect.ismethod(a))



  @classmethod
  def _getMethodDeclaration(cls, aMethod):
    try:
      name = aMethod.__name__
      spec = inspect.getargspec(aMethod)
      args = inspect.formatargspec(spec.args, spec.varargs, spec.keywords, spec.defaults)
      return '%s%s' % (name, args)
    except TypeError, e:
      return '%s(cls, ...)' % (name)



  @classmethod    
  def _checkImplementation(cls, aImplementation):
    """
    the implementation must implement at least all methods of this proxy,
    unless the methods is private ('_xxxx()') or it is marked as a proxy-method
    ('proxyXxxxxx()'); also check signature (must be identical).
    @param aImplementation: implementing object
    """
    missing = {}

    ours   = cls._getMethods(cls)
    theirs = cls._getMethods(aImplementation)

    for name, method in ours.iteritems():
        if not (theirs.has_key(name)):
          missing[name + "()"] = "not implemented"
          continue


        ourf   = cls._getMethodDeclaration(method)
        theirf = cls._getMethodDeclaration(theirs[name])

        if not (ourf == theirf):
          missing[name + "()"] = "method signature differs"

    if not (len(missing) == 0):
      raise Exception('incompatible Implementation-implementation %s: %s' % (aImplementation.__class__.__name__, missing))

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 1970-01-01
    • 2011-06-04
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 2011-09-08
    • 1970-01-01
    相关资源
    最近更新 更多