美文网首页
python 自动代理模式 仿静态代理自动实现

python 自动代理模式 仿静态代理自动实现

作者: 假程序员 | 来源:发表于2020-06-09 21:26 被阅读0次

    静态代理模式缺点:需要代理类与被代理类实现相同的接口,代码量大
    动态代理模式缺点:若被代理类实现了一些魔法方法,诸如iter, getitem时,代理实例将无法使用这些魔法特性。

    针对上述客观问题,本人设计并实现了自动代理模式,其吸取了静态代理模式的优点,弥补了动态代理模式的缺点,能够在代理同一类型的实例时提供良好的用户体验。以下代码代码在python2.7与3.7下调试通过,并能正确打印结果。其实现思路是:为代理实例创建与被代理实例同名的实例方法,为代理类创建与被代理类同名的实例方法,为代理类创建与被代理类同名的property。

    import types
    import inspect
    from sys import version_info
    
    
    class _NativeProxy(object):
        """not for user"""
    
        def __init__(self, target):
            cls = type(self)
            if cls is _NativeProxy:
                raise AssertionError("not _NativeProxy(target), but NativeProxy(target).")
            wrapped_class = getattr(cls, "wrapped_class", None)
            if not (wrapped_class is None or wrapped_class is type(target)):
                raise AssertionError("_NativeProxy class only for a type of target.")
            setattr(cls, "_target", target)
            for _ in dir(target):
                try:
                    attr = getattr(target, _)
                except Exception:
                    attr = None
                if _ in dir(self):  # implemented by cls
                    continue
                elif inspect.isroutine(attr):
                    exec("""
    def {}(self, *args, **kwargs): 
        _target = getattr(self, "_target")
        target = getattr(_target, "{}")
        return target(*args, **kwargs)
    locals()["proxy_method"] = {}""".format(_, _, _))
                    if version_info.major == 2:
                        setattr(cls, _, types.MethodType(locals()["proxy_method"], None, cls))
                        setattr(self, _, types.MethodType(locals()["proxy_method"], self, cls))
                    else:
                        setattr(cls, _, types.MethodType(locals()["proxy_method"], cls))
                        setattr(self, _, types.MethodType(locals()["proxy_method"], self))
                else:  # property
                    exec("""
    def {}(self):
        _target = getattr(self, "_target")
        target = getattr(_target, "{}")
        return target
    locals()["proxy_property"] = {}""".format(_, _, _))
                    exec("""
    def {}(self, value):
        _target = getattr(self, "_target")
        setattr(_target, "{}", value)
    locals()["proxy_property_set"] = {}""".format(_, _, _))
                    setattr(cls, _, property(locals()["proxy_property"], locals()["proxy_property_set"]))
            setattr(cls, "wrapped_class", type(target))
    
    
    def get_native_proxy_class():
        """"for user"""
        return type("NativeProxy", (_NativeProxy,), {})
    
    
    def NativeProxy(target):
        """for user"""
        return get_native_proxy_class()(target)
    
    
    class Subject(object):
        data = "1234567890"
    
        @property
        def p1(self):
            return self.p
    
        @p1.setter
        def p1(self, p):
            self.p = p
    
        def __init__(self):
            self.p = "abcdefghijklmn"
    
        def test1(self):
            return self.p, "test"
    
        @classmethod
        def test2(cls):
            return cls.data
    
        def __call__(self, *args, **kwargs):
            return "call"
    
        def __getitem__(self, item):
            return self.p[item]
    
        def __iter__(self):
            return iter(self.p)
    
        def __str__(self):
            return self.p
    
    
    if __name__ == '__main__':
        test = Subject()
        print(test.p1)
        proxy_object = NativeProxy(test)
        print(proxy_object)
        test.p1 = "hahahahahha"
        proxy_object.p1 = "9999"
        print(proxy_object.p1)
        print(proxy_object.data)
        print(proxy_object.test1())
        print(proxy_object.test2())
        print(proxy_object())
        print(proxy_object[1:5])
        for _ in proxy_object:
            print(_),
    
    
    

    相关文章

      网友评论

          本文标题:python 自动代理模式 仿静态代理自动实现

          本文链接:https://www.haomeiwen.com/subject/kdzetktx.html