Python 中的代理变量
Proxying variables in Python
我有一个 Python 对象,我想屏蔽任何内部和外部访问以及 运行 通过代理的每个请求。到目前为止,我使用了 this 段代码,效果很好。我将它子类化并使用我要代理的对象对其进行初始化。
遗憾的是,它不涵盖从代理对象内部发生访问的情况。
class A(object):
def do_something(self):
self.foo.perform_action()
class MyProxy(Proxy):
def __init__(self, obj):
super(MyProxy, self).__init__(obj)
self.proxy_foo = ProxyFoo(obj.foo)
def __getattribute__(self, item):
if item == 'foo':
return self.proxy_foo
return super(MyProxy, self).__getattribute__(item)
a = A()
myproxy = Proxy(a)
# do_something should work on proxy_foo, but it operates on a.foo
myproxy.do_something()
我能做些什么来改变它?
我认为这不是个好主意。我能想到的唯一方法是使用不同的 self
对象捕获 do_something
和 return 修改后的绑定方法的访问。这充其量会令人困惑,最坏的情况是会被破坏,因为这意味着当 A 尝试访问自己时,它实际上并不是在访问自己,而是代理。您可以使用当前代理 class 执行此操作,但您必须拦截对 do_something
的访问,而不是 foo
:
class MyProxy(Proxy):
def __init__(self, obj):
super(MyProxy, self).__init__(obj)
self.proxy_foo = 999
def __getattribute__(self, item):
#print("__getattribute__({}, {})".format(self, item))
if item == 'foo':
return self.proxy_foo
if item == 'do_something':
return functools.partial(object.__getattribute__(self, '_obj').__class__.do_something, self)
return super(MyProxy, self).__getattribute__(item)
a = A()
myproxy = MyProxy(a)
然后:
>>> myproxy.do_something()
999
这完全有效,因为代理 class 甚至代理 __class__
属性,导致代理伪装成被代理 class 的实例。即便如此,这意味着 myproxy.do_something()
会导致对 __getattribute__
的四次单独调用,如您所见,如果您取消注释该打印(一次获得 do_something
,内部生成的 __class__
,一个获得 foo
,还有一个获得 proxy_foo
)。您可以看到,如果您调用的方法实际上对任何属性执行任何操作,调用次数可能会迅速增加。此外,我不清楚它是否适用于所有情况(例如,class 方法、双下划线私有 class 级变量)。甚至可以想象,在极端情况下它会进入无限循环。
一般来说,代理旨在提供一种在使用对象的封闭操作中用一个对象替换另一个对象的方法。试图愚弄一个物体,使其相信它本身就是另一个物体,这是一个冒险的提议。您最好制作一个具有自己的 __getattribute__
的混合代理 class 来执行您想要的代理,然后制作一个 subclass 将其与 A 混合并使用其实例而不是 A 的实例。这取决于您尝试使用此代理实现的目标。
我有一个 Python 对象,我想屏蔽任何内部和外部访问以及 运行 通过代理的每个请求。到目前为止,我使用了 this 段代码,效果很好。我将它子类化并使用我要代理的对象对其进行初始化。
遗憾的是,它不涵盖从代理对象内部发生访问的情况。
class A(object):
def do_something(self):
self.foo.perform_action()
class MyProxy(Proxy):
def __init__(self, obj):
super(MyProxy, self).__init__(obj)
self.proxy_foo = ProxyFoo(obj.foo)
def __getattribute__(self, item):
if item == 'foo':
return self.proxy_foo
return super(MyProxy, self).__getattribute__(item)
a = A()
myproxy = Proxy(a)
# do_something should work on proxy_foo, but it operates on a.foo
myproxy.do_something()
我能做些什么来改变它?
我认为这不是个好主意。我能想到的唯一方法是使用不同的 self
对象捕获 do_something
和 return 修改后的绑定方法的访问。这充其量会令人困惑,最坏的情况是会被破坏,因为这意味着当 A 尝试访问自己时,它实际上并不是在访问自己,而是代理。您可以使用当前代理 class 执行此操作,但您必须拦截对 do_something
的访问,而不是 foo
:
class MyProxy(Proxy):
def __init__(self, obj):
super(MyProxy, self).__init__(obj)
self.proxy_foo = 999
def __getattribute__(self, item):
#print("__getattribute__({}, {})".format(self, item))
if item == 'foo':
return self.proxy_foo
if item == 'do_something':
return functools.partial(object.__getattribute__(self, '_obj').__class__.do_something, self)
return super(MyProxy, self).__getattribute__(item)
a = A()
myproxy = MyProxy(a)
然后:
>>> myproxy.do_something()
999
这完全有效,因为代理 class 甚至代理 __class__
属性,导致代理伪装成被代理 class 的实例。即便如此,这意味着 myproxy.do_something()
会导致对 __getattribute__
的四次单独调用,如您所见,如果您取消注释该打印(一次获得 do_something
,内部生成的 __class__
,一个获得 foo
,还有一个获得 proxy_foo
)。您可以看到,如果您调用的方法实际上对任何属性执行任何操作,调用次数可能会迅速增加。此外,我不清楚它是否适用于所有情况(例如,class 方法、双下划线私有 class 级变量)。甚至可以想象,在极端情况下它会进入无限循环。
一般来说,代理旨在提供一种在使用对象的封闭操作中用一个对象替换另一个对象的方法。试图愚弄一个物体,使其相信它本身就是另一个物体,这是一个冒险的提议。您最好制作一个具有自己的 __getattribute__
的混合代理 class 来执行您想要的代理,然后制作一个 subclass 将其与 A 混合并使用其实例而不是 A 的实例。这取决于您尝试使用此代理实现的目标。