Python:如何传递自动代理对象 [英] Python: How to pass an Autoproxy object
问题描述
我需要将一个对象的代理传递给另一个对象,但是每当执行此操作时,所有其他对象获得的就是代理的引用对象,而不是代理本身.这与我正在尝试执行的操作类似:
I need to pass the proxy of an object to another object but whenever I do this all the other object gets is the referent of the proxy and not the proxy itself. This is something similar to what I am trying to do:
import multiprocessing.managers as m
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar)
self.manager.start()
self.bar = self.manager.Bar()
self.bar.set_proxy(self.bar)
class Bar(object):
def __init__(self):
self.proxy = None
def set_proxy(self, proxy):
self.proxy = proxy
class MyManager(m.BaseManager):
pass
test = Foo()
每当执行此操作时,self.proxy
中的值就是我创建的Foo实例,而不是管理器返回的代理.
whenever I do this the value in self.proxy
is the instance of Foo that I created and not the proxy that was returned by the manager.
推荐答案
这是由于设计缺陷或 a错误,以取消Proxy
实例的方式.现在,如果解开代码看到您正在Manager
内部运行,则它为您提供解开时的参考对象,而不是Proxy
:
This is because of design flaw, or perhaps a bug, in the way Proxy
instances get unpickled. Right now, if the unpickling code see you're running inside a Manager
, it gives you the referent when you unpickle, rather than the Proxy
:
def RebuildProxy(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
If possible the shared object is returned, or otherwise a proxy for it.
'''
server = getattr(process.current_process(), '_manager_server', None)
if server and server.address == token.address:
return server.id_to_obj[token.id][0] # This returns the referent
else:
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds) # This returns the Proxy
有时候这可能是合乎需要的,但有时并非如此,就像您的情况一样.您可以通过替换ReduceProxy
函数来解决该问题,以解决该问题:
Sometimes this might be desirable, but sometimes its not, like it is in your case. You can work around it by replacing the ReduceProxy
function that does the unpickling in your program:
import multiprocessing.managers as m
from multiprocessing import process
def RebuildProxyNoReferent(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
The Proxy object is always returned.
'''
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds)
m.RebuildProxy = RebuildProxyNoReferent # Monkey-patch it
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar)
self.manager.start()
self.bar = self.manager.Bar()
print(type(self.bar))
self.bar.set_proxy(self.bar)
class Bar(object):
def __init__(self):
self.proxy = None
def set_proxy(self, proxy):
print("got {}".format(type(proxy)))
self.proxy = proxy
class MyManager(m.BaseManager):
pass
test = Foo()
如果您不想猴子打补丁,也可以将BaseProxy
子类化,尽管它的工作量更大:
If you don't want to monkey-patch, you can also subclass BaseProxy
, though its a bit more work:
import multiprocessing.managers as m
from multiprocessing.managers import BaseProxy
from multiprocessing import process
def RebuildProxyNoReferent(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
If possible the shared object is returned, or otherwise a proxy for it.
'''
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds)
class MyProxy(BaseProxy):
_exposed_ = ("set_proxy",)
def set_proxy(self, arg):
self._callmethod('set_proxy', (arg,))
def __reduce__(self):
ret = super(MyProxy, self).__reduce__()
# RebuildProxy is the first item in the ret tuple.
# So lets replace it, just for our proxy.
ret = (RebuildProxyNoReferent,) + ret[1:]
return ret
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar, MyProxy)
self.manager.start()
self.bar = self.manager.Bar()
print(type(self.bar))
self.bar.set_proxy(self.bar)
这篇关于Python:如何传递自动代理对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!