2010-05-03 10 views
7

मुझे 2 प्रकार के MixIns करने के लिए एक शानदार तरीका खोजने की जरूरत है।पायथन में MixIns करने के सुरुचिपूर्ण तरीके क्या हैं?

पहले:

class A(object): 
    def method1(self): 
     do_something() 

अब, एक MixInClassmethod1 ऐसा करने बनाना चाहिए: do_other() ->A.method1() ->do_smth_else() - जो कि मूल रूप से "रैप" बड़े समारोह। मुझे पूरा यकीन है कि इसके लिए एक अच्छा समाधान मौजूद होना चाहिए।

दूसरा: ->MixIn.method1 ->do_more()

class B(object): 
    def method1(self): 
     do_something() 
     do_more() 

इस मामले में, मैं MixInClass2 ही है, do_something() और do_more() के बीच सुई यानी .: do_something() सक्षम होना चाहते हैं। मैं समझता हूं कि शायद class B को संशोधित करने की आवश्यकता होगी - यह ठीक है, बस इसे प्राप्त करने के सबसे सरल तरीकों की तलाश है।

ये बहुत छोटी समस्याएं हैं और मैंने वास्तव में उन्हें हल किया है, लेकिन मेरा समाधान दंडित है।

self._old_method1 = self.method1(); self.method1() = self._new_method1(); का उपयोग करके Fisrt एक और _new_method1() लिखकर _old_method1() पर कॉल करें।

समस्या: एकाधिक MixIns सभी _old_method1 का नाम बदलेंगे और यह सुरुचिपूर्ण है।

दूसरा मिश्रण एक डमी विधि call_mixin(self): pass बनाकर हल किया गया था और इसे कॉल के बीच इंजेक्शन और self.call_mixin() परिभाषित किया गया था। फिर से सुरुचिपूर्ण और एकाधिक MixIns पर तोड़ देगा ..

कोई विचार?

class MixIn_for_1(object): 
    def __init__(self): 
     self.method1 = self.wrap1(self.method1) 
     super(MixIn_for_1, self).__init__() 

    def wrap1(self, old): 
     def method1(): 
      print "do_other()" 
      old() 
      print "do_smth_else()" 
     return method1 

अभी भी खोजा जा:


Boldewyn के लिए धन्यवाद, मैं पहली बार एक (मैं आप ऑन-द-मक्खी सज्जाकार बना सकते हैं भूल गए हैं मूल कोड को संशोधित करने के बिना,) करने के लिए सुरुचिपूर्ण समाधान मिल गया है दूसरे के लिए विचारों के लिए (यह विचार फिट नहीं होगा, क्योंकि मुझे पुरानी विधि के अंदर इंजेक्ट करने की आवश्यकता है, बाहर नहीं, इस मामले में)। दूसरे के लिए


समाधान lambda:0 के साथ "pass_func" की जगह नीचे है।

+0

अपने 2 प्रश्न के लिए, mixin.method1 मानकों की जरूरत है, और यदि हां, तो do_something में इन मानकों चर/वापसी मूल्यों पर निर्भर क्या करता है()? और अंत में, क्या do_more() आपके मिश्रण के परिणाम की आवश्यकता है? – KillianDS

+0

नहीं, do_more() को परिणाम की आवश्यकता नहीं है। तर्क? मुझे शायद केवल "स्वयं" की आवश्यकता है, जिसे वैसे भी पारित किया जाना चाहिए। –

उत्तर

3

यहाँ MixInClass1, MixinClass2 लागू करने के लिए एक और तरीका है। चूंकि MixinClass1 केवल एक समारोह रैप करने के लिए की जरूरत है, मुझे लगता है कि यह बंदर-पैच करने के लिए स्पष्ट है:

__old_method1 के लिए डबल अंडरस्कोर का उपयोग करना और __method1MixInClass1 में एक उपयोगी भूमिका निभाता है।पाइथन के नाम-सम्मेलन सम्मेलन के कारण, डबल अंडरस्कोर का उपयोग करके इन गुणों को MixinClass1 पर स्थानांतरित किया जाता है और आपको अनचाहे नाम-टकराव के बिना अन्य मिश्रण-कक्षाओं के लिए समान गुण नामों का उपयोग करने की अनुमति मिलती है।

class MixInClass1(object): 
    def __init__(self): 
     self.__old_method1,self.method1=self.method1,self.__method1 
     super(MixInClass1, self).__init__()   
    def __method1(self): 
     print "pre1()" 
     self.__old_method1() 
     print "post1()" 

class MixInClass2(object): 
    def __init__(self): 
     super(MixInClass2, self).__init__()   
    def method1_hook(self): 
     print('MixIn method1') 

class Foo(MixInClass2,MixInClass1): 
    def method1(self): 
     print "do_something()" 
     getattr(self,'method1_hook',lambda *args,**kw: None)() 
     print "do_more()" 

foo=Foo() 
foo.method1() 
+0

पहला समाधान बिल्कुल वही है जैसा मैंने प्रश्न में वर्णित किया है। दूसरा एक चालाक है, मानते हैं कि 'फू' 'बी' है और pass_func 'lambda: 0' है। –

+0

@ स्लावा: यदि आप 'pass_func' का उपयोग करते हैं, तो आपको 'विधि 1_hook' पर तर्क पारित करने का निर्णय लेने पर आपको' Foo 'को बदलना नहीं होगा। यदि आप 'lambda: 0' का उपयोग करते हैं तो आपको इसे' lambda x, y, z: 0' जैसे कुछ में बदलना होगा। – unutbu

+0

1. 'pass_func' क्या है? 2. क्या हम सिर्फ 'लैम्ब्डा * तर्क नहीं कर सकते हैं, ** kwargs: 0'? –

5

मुझे लगता है कि इसे decorators का उपयोग करके काफी पाइथनिक तरीके से संभाला जा सकता है। जब आप कई कार्यों रैप करने के लिए की जरूरत है

डेकोरेटर उपयोगी होते हैं: (PEP 318, भी)

+0

धन्यवाद, जो मेरी पहली समस्या हल करता है। मैंने वास्तव में सजावट करने वालों के बारे में सोचा था, लेकिन मैं भूल गया था कि मैं @deco के बजाय सजावटकारों को डेको (विधि) के रूप में बना सकता हूं। बाद वाले को मूल कोड संशोधित करने की आवश्यकता थी। –

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