2014-10-22 18 views
8

की एक बहु प्रॉक्सी की एक विशेषता को एक्सेस करना मैं एक वर्ग है कि मैं केवल पढ़ने के लिए फैशन में साझा करने के लिए बच्चों को एक पूल में प्रक्रियाओं के साथ करना चाहते हैं, तो मैं एक वर्ग के एक प्रॉक्सी तैयार है, लेकिन यह काम नहीं किया। निम्नलिखित मेरी समस्या का सरलीकृत उदाहरण है।एक वर्ग

from multiprocessing.managers import BaseManager 

class TestClass: 
    def __init__(self, a): 
     self.a = a 
    def b(self): 
     print self.a 

class MyManager(BaseManager): pass 

MyManager.register('test', TestClass) 

if __name__ == '__main__': 
    manager = MyManager() 
    manager.start() 
    t = TestClass(1) 
    print t.a 
    mt = manager.test(2) 
    mt.b() 
    mt.a 

मुझे इस कोड को चलाने मैं:

1 
2 
Traceback (most recent call last): 
    File "multiprocess_example_stackexchange.py", line 20, in <module> 
    mt.a 
AttributeError: 'AutoProxy[test]' object has no attribute 'a' 

ऐसा लगता है कि मैं एक प्रॉक्सी के माध्यम से सीधे एक साझा वस्तु की विशेषता का उपयोग नहीं कर सकते हैं। एक ही तरीका है एक विधि उस गुण हो जाता है उपयोग कर रहा है, या मैं कुछ गलत कर रहा हूँ?

उत्तर

9

Proxy वस्तुओं multiprocessing.BaseManager और उसके उप-वर्गों द्वारा इस्तेमाल किया सामान्य रूप से केवल तरीकों वस्तुओं वे करने के लिए, नहीं विशेषताओं की बात कर रहे हैं, उससे बेनकाब। अब, वहाँ multiprocessing.Manager().Namespace है, जो एक Proxy उप-वर्ग कि , गुण के लिए पहुँच प्रदान करता है बल्कि तरीकों की तुलना में प्रदान करता है। हम अपने b कार्य करने के लिए अपने स्वयं के Proxy प्रकार है जो कि से विरासत है, जो हमारे सभी विशेषताओं तक पहुंच प्रदान करता है, साथ ही पहुँच बना सकते हैं:

from multiprocessing.managers import BaseManager, NamespaceProxy 

class TestClass(object): 
    def __init__(self, a): 
     self.a = a 

    def b(self): 
     print self.a 

class MyManager(BaseManager): pass 

class TestProxy(NamespaceProxy): 
    # We need to expose the same __dunder__ methods as NamespaceProxy, 
    # in addition to the b method. 
    _exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'b') 

    def b(self): 
     callmethod = object.__getattribute__(self, '_callmethod') 
     return callmethod('b') 

MyManager.register('test', TestClass, TestProxy) 

if __name__ == '__main__': 
    manager = MyManager() 
    manager.start() 
    t = TestClass(1) 
    print t.a 
    mt = manager.test(2) 
    print mt.a 
    mt.a = 5 
    mt.b() 

आउटपुट:

1 
2 
5 

संपादित करें:

आप गतिशील रूप से एक प्रॉक्सी वर्ग के लिए अपने मूल वर्ग से तरीकों जोड़ने में सक्षम होना चाहते हैं, तो आप कुछ इस तरह कर सकते हैं:

from multiprocessing.managers import BaseManager, NamespaceProxy 
import inspect 

class TestClass(object): 
    def __init__(self, a): 
     self.a = a 

    def b(self): 
     print self.a 

class AnotherClass(object): 
    def __init__(self, a): 
     self.a = a 

    def c(self): 
     print self.a 

class MyManager(BaseManager): pass 

class ProxyBase(NamespaceProxy): 
    _exposed_ = ('__getattribute__', '__setattr__', '__delattr__') 

class TestProxy(ProxyBase): pass 
class AnotherProxy(ProxyBase): pass 


def register_proxy(name, cls, proxy): 
    for attr in dir(cls): 
     if inspect.ismethod(getattr(cls, attr)) and not attr.startswith("__"): 
      proxy._exposed_ += (attr,) 
      setattr(proxy, attr, 
        lambda s: object.__getattribute__(s, '_callmethod')(attr)) 
    MyManager.register(name, cls, proxy) 

register_proxy('test', TestClass, TestProxy) 
register_proxy('another', AnotherClass, AnotherProxy) 

if __name__ == '__main__': 
    manager = MyManager() 
    manager.start() 
    mt = manager.test(2) 
    ma = manager.another(3) 
    mt.b() 
    ma.c() 
    mt.a = 5 
    ma.a = 6 
    mt.b() 
    ma.c() 
+0

बहुत बहुत शुक्रिया द्वारा a का उपयोग करने की अनुमति देता है! –

+0

क्या होगा यदि मैं और विशेषताओं के एक दर्जन से अधिक तरीकों के दर्जनों है? क्या मुझे टेस्टप्रॉक्सी कक्षा में उन्हें सब लिखना है? या क्या एक और सामान्य समाधान है? – selotec

+0

@selotec मैं समय वास्तव में एक कार्यान्वयन प्रदान करने के लिए नहीं है, लेकिन आप अपने वर्ग की सभी विशेषताओं से अधिक सक्षम पुनरावृति होना चाहिए, और गतिशील रूप से आपकी प्रॉक्सी वर्ग के लिए पाए जाने वाले तरीकों जोड़ सकते हैं और '_exposed' चर – dano

0

यहाँ एक कम वर्बोज़ विकल्प है कि मैं व्यवहार में अच्छी तरह से काम करने के लिए मिला है। सुनिश्चित नहीं है कि कोई नुकसान है या नहीं।

class TestClass: 
    def __init__(self, a): 
     self.a = a 
    def b(self): 
     print self.a 

def wrap_test_class(*args, **kwargs): 
    obj = TestClass(*args, **kwargs) 
    obj.get_a = lambda: obj.a 
    return obj 

class MyManager(BaseManager): pass 

MyManager.register('test', wrap_test_class) 

यह आपको बुला proxy_object.get_a()

संबंधित मुद्दे