2009-09-18 31 views
23

मैं पूरी तरह से एक वस्तु रैप करने के लिए इतना है कि सभी विशेषता और विधि अनुरोध वस्तु को अग्रेषित करने के लिए यह लपेटकर है, लेकिन यह भी किसी भी तरीके या चर कि मैं चाहता हूँ अधिभावी, साथ ही के कुछ उपलब्ध कराने के लिए इच्छुक हूँ में एक वस्तु लपेट मेरी अपने तरीके यह आवरण वर्ग, मौजूदा वर्ग (जैसे कि यह वास्तव में वर्ग है isinstance कार्य करना चाहिए) के रूप में 100% दिखाई देनी चाहिए लेकिन उपवर्गीकरण में ही है, यह कटौती करने के लिए नहीं जा रहा है के रूप में मैं एक मौजूदा वस्तु रैप करने के लिए चाहते हैं। क्या ऐसा करने के लिए पाइथन में कुछ समाधान है? मैं की तर्ज पर कुछ सोच रहा था:पूरी तरह से अजगर

class ObjectWrapper(BaseClass): 
    def __init__(self, baseObject): 
     self.baseObject = baseObject 

    def overriddenMethod(self): 
     ... 

    def myOwnMethod1(self): 
     ... 

    ... 

    def __getattr__(self, attr): 
     if attr in ['overriddenMethod', 'myOwnMethod1', 'myOwnMethod2', ...] 
      # return the requested method 
     else: 
      return getattr(self.baseObject, attr) 

लेकिन मुझे लगता है कि अधिभावी __getattr__, __setattr__ और __hasattr__ से परिचित नहीं हूँ, इसलिए मुझे यकीन है कि कैसे यह सही पाने के लिए नहीं कर रहा हूँ।

+0

[इस सवाल] (http://stackoverflow.com/questions/1382871/dynamically-attaching-a-method-to-an-existing-python-object- को मेरा उत्तर देखें उत्पन्न-साथ-बड़ा घूँट/1383646 # 1383646)। – PaulMcG

उत्तर

4

__getattr__ का लाभ यह है कि यह केवल तब कहा जाता है जब विशेषता मौजूद नहीं होती है, इसलिए आपको एक स्पष्ट सूची की आवश्यकता नहीं होनी चाहिए - जो भी आप परिभाषित नहीं करते हैं, वह स्वचालित रूप से प्रॉक्सी हो जाएगा। क्योंकि यह हमेशा कहा जाता है

__setattr__ जटिल काम है। सुनिश्चित करें कि आप अपने गुणों को सेट करते समय सुपरक्लास कॉल या object.__setattr__ का उपयोग करें; __setattr__ भीतर setattr() का उपयोग कर अनंत प्रत्यावर्तन का कारण होगा।

अंतिम बिट, isinstance को प्रभावित करने, बहुत मुश्किल है। आप इसे अपने रैपर उदाहरण के लिए एक अभिसरण के साथ कर सकते हैं। __class__ चर (लेकिन यह भी वर्ग शब्दकोश संकल्प आदेश ओवरराइड करता है), या गतिशील रूप से एक metaclass का उपयोग कर अपने आवरण प्रकार का निर्माण करके। चूंकि पाइथन कोड में इंस्टेंसेंस इतना दुर्लभ है, इसलिए वास्तव में यह चाल करने की कोशिश करने के लिए बहुत अधिक लगता है।

Even more information on them, plus some help with metaclasses.

0

'मौजूदा ऑब्जेक्ट' करके आप किसी अन्य वर्ग का एक उदाहरण क्या मतलब है? मुझे लगता है कि आपको केवल बेस क्लास से उत्तराधिकारी होना चाहिए। जब आप अपनी नई वस्तु बनाते हैं, तो बेस ऑब्जेक्ट के विवरण में पास करें, या अपनी नई कक्षा में एक विधि जोड़ें जो बेस क्लास इंस्टेंस के डेटा को स्वयं में कॉपी करता है।

+0

अगर यह केवल इतना आसान था। जिस कक्षा में मैं लपेट रहा हूं वह एक तिहाई पार्टी है, और मेरा मानना ​​है कि यह सी में लिखा गया है। यह पूरी ढेर को कठिन बनाता है (और जब हम तीसरे पक्ष के पुस्तकालय के नए संस्करण में अपडेट होते हैं तो यह बदल सकता है, और मैं चाहता हूं इसके बजाए हमारे कोड को भी बदलना नहीं है।) – Smashery

+0

मुझे लगता है कि यह मामला हो सकता है .. इसलिए मूल रूप से आप किसी मौजूदा वर्ग में एक इंटरफ़ेस बनाना चाहते हैं। इस मामले में, आपका सुझाव शायद इसके बारे में जाने का एक साफ तरीका है। शुभकामनाएं :-) –

2

इस और पाश में सामान के साथ गड़बड़ के साथ प्रारंभ आपकी आवश्यकताओं के अनुरूप:

import inspect 
class Delegate(object): 
    def __init__(self, implementation): 
     self.__class__ = implementation.__class__ 
     for n, m in inspect.getmembers(implementation, callable): 
      if not n.startswith('_'): 
       setattr(self, n, m) 

नहीं-नई शैली-वस्तुओं लपेटो करने की क्षमता पाठक :)

31
लिए एक व्यायाम के रूप में छोड़ दिया जाता है

ज्यादातर मामलों में सबसे आसान तरीका शायद है:

class ObjectWrapper(BaseClass): 
    def __init__(self, baseObject): 
     self.__class__ = type(baseObject.__class__.__name__, 
           (self.__class__, baseObject.__class__), 
           {}) 
     self.__dict__ = baseObject.__dict__ 

    def overriddenMethod(self): 
     ... 

, इस तरह से कार्य करना स्वयं के __class__ और __dict__, आप n फिर नियत इस फैशन में अर्थात् ईद केवल आपके ओवरराइड प्रदान करते हैं - पाइथन की सामान्य विशेषता प्राप्त करने और तंत्र को व्यवस्थित करने के लिए बाकी ... अधिकतर

आप मुसीबत में हो जाएगा केवल अगर baseObject.__class____slots__, जिस स्थिति में एकाधिक वंशानुक्रम दृष्टिकोण काम नहीं करता है परिभाषित करता है और आप की जरूरत है बोझिल __getattr__ (के रूप में अन्य लोगों ने कहा, कम से कम आप यह है कि चिंता करने की जरूरत नहीं है उन गुणों के साथ बुलाया जाएगा जिन्हें आप ओवरराइड कर रहे हैं, क्योंकि यह नहीं होगा! -), __setattr__ (एक बड़ा दर्द, क्योंकि यह प्रत्येक विशेषता के लिए बुलाया जाता है), आदि; और isinstance बनाने और विशेष तरीकों के काम में दर्दनाक और बोझिल विस्तृत काम होता है।

अनिवार्य रूप से, __slots__ मतलब यह है कि एक वर्ग, एक विशेष, प्रत्येक उदाहरण के एक हल्के "मूल्य वस्तु" नहीं आगे परिष्कृत हेरफेर, रैपिंग, आदि के अधीन किया जा सकता है कि वर्ग ओवरराइड के कहने के अनुसार कुछ बाइट्स को बचाने के लिए की जरूरत है क्योंकि लचीलापन के बारे में सभी सामान्य चिंताओं और इतने पर; इसलिए यह आश्चर्य की बात नहीं है कि एक ही चिकनी और लचीली तरीके से ऐसी चरम, दुर्लभ कक्षाओं से निपटने के रूप में आप 99% + पाइथन वस्तुओं से निपट सकते हैं वास्तव में एक दर्द है। तो क्या आपको __slots__ (लिखने, परीक्षण, डिबगिंग और उन कोने मामलों के लिए कोड की सैकड़ों लाइनों को बनाए रखने के बिंदु से निपटने के लिए) की आवश्यकता है), या आधे दर्जन लाइनों में 99% समाधान पर्याप्त होगा? -)

यह भी ध्यान दिया जाना चाहिए कि इससे मेमोरी लीक हो सकता है, क्योंकि उप-वर्ग बनाने से सबक्लास को वर्ग वर्ग की उप-वर्ग की सूची में जोड़ दिया जाता है, और उप-वर्ग के सभी उदाहरण जीसीएड होने पर हटा नहीं जाते हैं।

+0

क्या कोई व्यक्ति इस दृष्टिकोण को और गहराई से समझा सकता है? आप कैसे जानते हैं कि __dict__ पहले असाइन किया गया है? \ _ \ _ Init \ _ \ _ के लिए कॉल में से एक? या निहित एक? – dspyz

+0

मुझे यह दृष्टिकोण भी वर्बोज़ और कुछ हद तक गूढ़ लगता है। [मेरे सुझाव] के बारे में आप क्या सोचते हैं (http://stackoverflow.com/a/31437314/17523)? –

+1

@bgbg, आपका दृष्टिकोण ओ * अनुरोध के रूप में एक * ऑब्जेक्ट * नहीं, * ऑब्जेक्ट * को लपेटता है। –

0

निम्नलिखित दृष्टिकोण the one by Alex Martelli के समान है, लेकिन मेरे लिए अधिक पठनीय है: इसके बजाय एक नया वर्ग पैदा करने की

, मैं, एक वर्ग की तरह समारोह है कि अंतर्निहित वस्तु को दर्शाता है और जरूरत कार्यों अधिलेखित कर देता है बनाने के इस प्रकार है:

class C1: 
    def __init__(self, p): 
     self.p = p 
    def f(self): 
     print("This is C1, p=%s" % self.p) 

def C2(p): 
    c = C1(p) 
    def new_f(): 
     print("This is C2, p is %s" % c.p) 
    c.f = new_f 
    def g(param): 
     print("This is C2.g(%s), p is %s" % (param, c.p)) 
    c.g = g 
    return c 

c1 = C1('abc') 
c1.f() 

c2 = C2('cde') 
c2.f() 
c2.g('xyz') 

उत्पादन:

This is C1, p=abc 

This is C2, p is cde 
This is C2.g(xyz), p is cde 
1

कृपया पूरा कोड के लिए http://code.activestate.com/recipes/577555-object-wrapper-class/ को देखो, importa सहित एनटी टिप्पणियां यह करने पर निर्भर करता:

class Wrapper(object): 
    def __init__(self, obj): 
     self._wrapped_obj = obj 
    def __getattr__(self, attr): 
     if attr in self.__dict__: 
      return getattr(self, attr) 
     return getattr(self._wrapped_obj, attr) 
+1

यह एक अच्छा तरीका है, आपको यह जांचने की ज़रूरत नहीं है कि क्या एटीआर dict में है या नहीं। '__getattr__' केवल तभी बुलाया जाता है जब एट्रिब्यूट dict में नहीं है। –

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