静态代理模式缺点:需要代理类与被代理类实现相同的接口,代码量大
动态代理模式缺点:若被代理类实现了一些魔法方法,诸如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(_),
网友评论