2015-04-22 3 views
1

Мне нужно передать прокси объекта другому объекту, но всякий раз, когда я делаю это, все остальные объекты получают референт прокси, а не сам прокси. Это нечто похожее на то, что я пытаюсь сделать:Python: Как передать объект Autoproxy

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, который я создал, а не прокси, который был возвращен менеджером.

+0

Извините, я не понял ваш вопрос. Как вы сказали, проблема находится где-то перед 'self.bar.set_proxy (...)', так что вы можете оставить класс 'MyManager()'? – khajvah

+0

Класс MyManager() - это просто подкласс многопроцессорности.BaseManager(), но я добавлю его, если это поможет. – user2909415

ответ

1

Это из-за недостатка дизайна, или, может быть, a bug, на пути Proxy экземпляры становятся незаселенными. Прямо сейчас, если unpickling код видит, что вы работаете внутри Manager, это дает вам референт, когда вы unpickle, а не 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, которая делает unpickling в программе:

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, хотя его немного больше работы:

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) 
+0

Спасибо за ответ и объяснение. Я думаю, что это уже третий раз, когда вы успешно ответили на один из моих вопросов, и во второй раз, когда вы поняли, что это ошибка; ты удивительный! – user2909415