开发者社区> 问答> 正文

属性的代理访问

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

展开
收起
哦哦喔 2020-04-17 15:06:27 725 0
1 条回答
写回答
取消 提交回答
  • 简单来说,代理是一种编程模式,它将某个操作转移给另外一个对象来实现。 最简单的形式可能是像下面这样:
    
    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__() 方法或许或更好些:
    
    class B2:
        """使用__getattr__的代理,代理方法比较多时候"""
    
        def __init__(self):
            self._a = A()
    
        def bar(self):
            pass
    
        # Expose all of the methods defined on class A
        def __getattr__(self, name):
            """这个方法在访问的attribute不存在的时候被调用
            the __getattr__() method is actually a fallback method
            that only gets called when an attribute is not found"""
            return getattr(self._a, name)
    __getattr__ 方法是在访问attribute不存在的时候被调用,使用演示:
    
    b = B()
    b.bar() # Calls B.bar() (exists on B)
    b.spam(42) # Calls B.__getattr__('spam') and delegates to A.spam
    另外一个代理例子是实现代理模式,例如:
    
    # A proxy class that wraps around another object, but
    # exposes its public attributes
    class Proxy:
        def __init__(self, obj):
            self._obj = obj
    
        # Delegate attribute lookup to internal obj
        def __getattr__(self, name):
            print('getattr:', name)
            return getattr(self._obj, name)
    
        # Delegate attribute assignment
        def __setattr__(self, name, value):
            if name.startswith('_'):
                super().__setattr__(name, value)
            else:
                print('setattr:', name, value)
                setattr(self._obj, name, value)
    
        # Delegate attribute deletion
        def __delattr__(self, name):
            if name.startswith('_'):
                super().__delattr__(name)
            else:
                print('delattr:', name)
                delattr(self._obj, name)
    使用这个代理类时,你只需要用它来包装下其他类即可:
    
    class Spam:
        def __init__(self, x):
            self.x = x
    
        def bar(self, y):
            print('Spam.bar:', self.x, y)
    
    # Create an instance
    s = Spam(2)
    # Create a proxy around it
    p = Proxy(s)
    # Access the proxy
    print(p.x)  # Outputs 2
    p.bar(3)  # Outputs "Spam.bar: 2 3"
    p.x = 37  # Changes s.x to 37
    通过自定义属性访问方法,你可以用不同方式自定义代理类行为(比如加入日志功能、只读访问等)。
    
    2020-04-17 15:06:36
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载