最近开始学习python,发现python很方便,提供了丰富的函数支持反射,本人之前主要以java编程为主,在学习python的过程中,学习到了Python的装饰器,结合之前java的代理模式,于是想要编写基于python的对象代理
代理模式的理论知识网上有很多相关的材料,总而言之就是对象有一个配套的代理对象,对代理对象进行调用时,代理对象转发调用给实际对象本身
下面介绍一些自己写的一些类:
ProxyFactory 传入hcls(被装饰类的处理器类型)作为init的参数, 传入 cls(被装饰类的类型)作为call的参数
class ProxyFactory: def __init__(self, hcls): if issubclass(hcls, InvocationHandler) or hcls is InvocationHandler: self.hcls = hcls else: raise HandlerException(hcls) def __call__(self, cls): return Proxy(cls, self.hcls)
Proxy 传入cls(被装饰类的类型)、hcls(被装饰类的处理器类型)作为init的参数
class Proxy: def __init__(self, cls, hcls): self.cls = cls self.hcls = hcls self.handlers = dict() def __call__(self, *args, **kwargs): self.obj = self.cls(*args, **kwargs) return self def __getattr__(self, attr): print('get attr', attr) isExist = hasattr(self.obj, attr) res = None if isExist: res = getattr(self.obj, attr) if isinstance(res, MethodType): if self.handlers.get(res) is None: self.handlers[res] = self.hcls(self.obj, res) return self.handlers[res] else: return res return res
InvocationHandler 传入func(被装饰类的实例方法)作为init的参数
class InvocationHandler: def __init__(self, obj, func): self.obj = obj self.func = func def __call__(self, *args, **kwargs): print('handler:',self.func, args, kwargs) return self.func(*args, **kwargs)
HandlerException 处理器异常
class HandlerException(Exception): def __init__(self, cls): super(HandlerException, self).__init__(cls, 'is not a hanlder class')
Sample
@ProxyFactory(InvocationHandler) class Sample: def __init__(self, age): self.age = age def foo(self): print('hello', self.age) def add(self, x, y): return x + y s = Sample(12) print(type(s)) s.foo() s.add(1,2) s.add(2,4) print(s.age)
结果:
<class '__main__.Proxy'> get attr foo handler: <bound method Sample.foo of <__main__.Sample object at 0x000000B354B54BE0>> () {} hello 12 get attr add handler: <bound method Sample.add of <__main__.Sample object at 0x000000B354B54BE0>> (1, 2) {} get attr add handler: <bound method Sample.add of <__main__.Sample object at 0x000000B354B54BE0>> (2, 4) {} get attr age 12
可以看到 s的类型是Proxy,而不是Sample 当调用s.foo方法时, 首先调用Proxy中的getattr方法, 然后被handler的call方法处理