什么是Python中最简单的转发类定义?

时间:2015-08-02 20:46:33

标签: python

我希望在Python中实现转发类,实现一些基类,它在构造函数中接受同一基类的另一个实现,并为基类中的每个方法转发到该类。

这对于提供自定义点,为某些方法添加缓存,在每个调用站点中记录等等非常有用。

手动编写此内容非常简单。鉴于此基类:

class BaseClass(object):
    def method_a(self, *args):
        pass

    @property
    def prop_b(self):
        pass

    def method_c(self, a, b, **kwargs):
        pass

这是一个简单的转发实施。

class ForwardBaseClass(BaseClass):
    def __init__(self, underlying_implementation):
        self._impl = underlying_implementation

    def method_a(self, *args):
        return self._impl.method_a(*args)

    @property
    def prop_b(self):
        return self._impl.prop_b

    def method_c(self, a, b, **kwargs):
        return self._impl.method_c(a, b, **kwargs)

编写代码的缺点是有很多样板代码,并且必须为每个方法编写代码。随着方法被添加到基类中,类似的代码必须被添加到转发类中;如果需要对类的转发方式进行更改,则必须通过所有方法进行传播。 (例如,想象一下,我们想要更改类,以便它在每次调用时都使用了一个上下文管理器。)

是否有一种简短的Pythonic方式,无论是基本语言,内置模块还是PyPI上的一些可靠模块?

所需功能:

  • 确切的方法签名
    • 转发的签名应与基类匹配
    • 每个签名上都没有*args, **kwargs
  • 正确包装@property装饰器的方法
  • __<method>__方法(如果存在)正确包装
  • 对于直接实施,每次方法调用无需额外费用
  • dir(instance)与直接实施完全相同

很高兴:

  • 基类不符合某些必要条件的错误消息
  • 有意义的docstrings
  • 从结果对象派生的能力
  • @staticmethod装饰器的方法转发到传入实现的类
  • @classmethod装饰器的方法转发到传入实现的类
  • __init____new__未转发

可能存在额外复杂性的地方:

  • 基类有一个元类
  • 基类有自己的多个基类
  • 一些更深奥的__<method>__及其语义

不要真心关心:

  • 多个基类
  • @property@staticmethod@classmethod
  • 以外的自定义描述符装饰器
  • 转发类创建后对基类的修改

1 个答案:

答案 0 :(得分:0)

只是为了澄清我的评论:我的意思是+/-这个(虽然需要更多工作......再次:可能无法满足您的所有要求):

class BaseClass(object):
    def method_a(self, *args):
        pass

    @property
    def prop_b(self):
        pass

    def method_c(self, a, b, **kwargs):
        pass

class ForwardBaseClass(BaseClass):
    def __init__(self, underlying_implementation):
        self._impl = underlying_implementation

    def __getattr__(self, name):
        # here you may have to exclude thigs; i.e. forward them to
        # self.name instead for self._impl.name
        try:
            return getattr(self._impl, name)
        except AttributeError:
            # do something else...

bc = BaseClass()
fbc = ForwardBaseClass(bc)
print(fbc.prop_b)
print(fbc.method_c(1,2,c=5))
print(dir(fbc))

请注意,由于python name mangling,您将无法以__这种方式访问​​成员。