8.15 属性的代理访问

问题

你想将某个实例的属性访问代理到内部另一个实例中去,目的可能是作为继承的一个替代方法或者实现代理模式。

解决方案

简单来说,代理是一种编程模式,它将某个操作转移给另外一个对象来实现。 最简单的形式可能是像下面这样:

class A:
    def spam(self, x):
        pass

    def foo(self):
        pass


class B1:
    """简单的代理"""

    def __init__(self):
        self._a = A()

    def spam(self, x):
        # Delegate to the internal self._a instance
        return self._a.spam(x)

    def foo(self):
        # Delegate to the internal self._a instance
        return self._a.foo()

    def bar(self):
        pass

如果有大量的方法需要代理, 那么使用 __getattr__() 方法或许或更好些:

__getattr__ 方法是在访问attribute不存在的时候被调用。

另外一个代理例子是实现代理模式,例如:

使用这个代理类时,你只需要用它来包装下其他类即可:

通过自定义属性访问方法,你可以用不同方式自定义代理类行为(比如加入日志功能、只读访问等)。

讨论

代理类有时候可以作为继承的替代方案。

当实现代理模式时,还有些细节需要注意。 首先,__getattr__() 实际是一个后备方法,只有在属性不存在时才会调用。 因此,如果代理类实例本身有这个属性的话,那么不会触发这个方法的。 另外,__setattr__()__delattr__() 需要额外的魔法来区分代理实例和被代理实例 _obj 的属性。 一个通常的约定是只代理那些不以下划线 _ 开头的属性(代理类只暴露被代理类的公共属性)。

还有一点需要注意的是,__getattr__() 对于大部分以双下划线(__)开始和结尾的属性并不适用。

为了让它支持这些方法,你必须手动的实现这些方法代理:

Last updated

Was this helpful?