Python:如何传递自动代理对象 [英] Python: How to pass an Autoproxy object

查看:89
本文介绍了Python:如何传递自动代理对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将一个对象的代理传递给另一个对象,但是每当执行此操作时,所有其他对象获得的就是代理的引用对象,而不是代理本身.这与我正在尝试执行的操作类似:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆