दिलचस्प पोस्ट
जावास्क्रिप्ट में मैं क्वेरी स्ट्रिंग मान कैसे प्राप्त करूं? कैसे लाइनों की UILabel की संख्या को खोजने के लिए एक तंत्रिका नेट पर स्पष्टीकरण जो सांप का निभाता है जावास्क्रिप्ट से सी # फ़ंक्शन कैसे कॉल करें? एंड्रॉइड में बिटमैप छवियों की तुलना करना Yii2 htaccess – कैसे फ्रंटएण्ड / वेब और बैकएंड / वेब पूरी तरह से छिपाने के लिए IBeacons के लिए त्रिकोण उदाहरण क्यों नहीं रतुआ वस्तु वस्तु upcasting का समर्थन करता है? जबकि एक के बाहर तोड़ … Wend पाश UimodalTransitionStylePartialCurl पिछले स्थिति में वापस नहीं मिलता है। (खारिज नहीं) जावा में डेटा और पाठ के लिए समन्वय विमान घुमाने के लिए एक ही TextView में तार के विभिन्न फ़ॉन्ट आकार क्या मुझे सारिका या इंट की प्राथमिक कुंजी के साथ तालिका तैयार करनी चाहिए? IPhone पर संपीड़न एपीआई गीत में हेड, काम कर पेड़ और सूचकांक के बीच अंतर क्या है?

बंदर पायथन में दूसरे मॉड्यूल में एक क्लास को पैचिंग करना

मैं किसी और के द्वारा लिखे गए मॉड्यूल के साथ काम कर रहा हूं। मैं बंदर पैच मॉड्यूल में परिभाषित वर्ग के __init__ विधि पसंद करना चाहते हैं। मैंने जो उदाहरण दिखाए हैं कि यह कैसे करना है, यह सब मानते हैं कि मैं खुद को क्लास को बुलाऊंगा (जैसे मकर-पैच पायथन क्लास )। बहरहाल, मामला यह नहीं। मेरे मामले में कक्षा किसी अन्य मॉड्यूल में एक फ़ंक्शन के भीतर आभासी है। निम्न (बहुत सरलीकृत) उदाहरण देखें:

thirdpartymodule_a.py

 class SomeClass(object): def __init__(self): self.a = 42 def show(self): print self.a 

thirdpartymodule_b.py

 import thirdpartymodule_a def dosomething(): sc = thirdpartymodule_a.SomeClass() sc.show() 

mymodule.py

 import thirdpartymodule_b thirdpartymodule.dosomething() 

क्या कुछ dosomething पद्धति को संशोधित करने का कोई तरीका है, जब कि dosomething को dosomething से कहा जाता है, उदाहरण के लिए, 42 के स्थान पर 43 प्रिंट करता है? आदर्श रूप से मैं मौजूदा विधि को लपेट कर पा रहा हूं।

मैं तृतीयpartymodule * .i फ़ाइलों को बदल नहीं सकता, क्योंकि अन्य स्क्रिप्ट मौजूदा कार्यक्षमता पर निर्भर करते हैं मुझे मॉड्यूल की अपनी प्रतिलिपि बनाने की ज़रूरत नहीं थी, क्योंकि मुझे जो परिवर्तन करने की ज़रूरत है वह बहुत सरल है।

2013-10-24 को संपादित करें

मैंने ऊपर दिए गए उदाहरण में एक छोटी लेकिन महत्वपूर्ण जानकारी को अनदेखा किया SomeClass इस तरह thirdpartymodule_b द्वारा उपयोग किया जाता है: from thirdpartymodule_a import SomeClass

एफजे द्वारा सुझाए गए पैच को करने के लिए मुझे thirdpartymodule_b बजाय प्रतिलिपि को प्रतिस्थापित करना होगा। जैसे thirdpartymodule_b.SomeClass.__init__ = new_init । कुछ thirdpartymodule_b.SomeClass.__init__ = new_init

वेब के समाधान से एकत्रित समाधान "बंदर पायथन में दूसरे मॉड्यूल में एक क्लास को पैचिंग करना"

निम्नलिखित कार्य करना चाहिए:

 import thirdpartymodule_a import thirdpartymodule_b def new_init(self): self.a = 43 thirdpartymodule_a.SomeClass.__init__ = new_init thirdpartymodule_b.dosomething() 

यदि आप चाहते हैं कि नए init को पुराने init को कॉल करने के लिए new_init() परिभाषा को निम्न के साथ बदलें:

 old_init = thirdpartymodule_a.SomeClass.__init__ def new_init(self, *k, **kw): old_init(self, *k, **kw) self.a = 43 

mock लाइब्रेरी का उपयोग करें

 import thirdpartymodule_a import thirdpartymodule_b import mock def new_init(self): self.a = 43 with mock.patch.object(thirdpartymodule_a.SomeClass, '__init__', new_init): thirdpartymodule_b.dosomething() # -> print 43 thirdpartymodule_b.dosomething() # -> print 42 

या

 import thirdpartymodule_b import mock def new_init(self): self.a = 43 with mock.patch('thirdpartymodule_a.SomeClass.__init__', new_init): thirdpartymodule_b.dosomething() thirdpartymodule_b.dosomething() 

गंदा, लेकिन यह काम करता है:

 class SomeClass2(object): def __init__(self): self.a = 43 def show(self): print self.a import thirdpartymodule_b # Monkey patch the class thirdpartymodule_b.thirdpartymodule_a.SomeClass = SomeClass2 thirdpartymodule_b.dosomething() # output 43 

एक ही थोड़ा-कम-हैमी संस्करण केवल पैरामीटर के रूप में वैश्विक चर का उपयोग करता है:

 sentinel = False class SomeClass(object): def __init__(self): global sentinel if sentinel: <do my custom code> else: # Original code self.a = 42 def show(self): print self.a 

जब प्रहरी झूठ है, यह पहले जैसा ही कार्य करता है जब यह सत्य है, तो आपको अपना नया व्यवहार मिलता है। आपके कोड में, आप ऐसा करेंगे:

 import thirdpartymodule_b thirdpartymodule_b.sentinel = True thirdpartymodule.dosomething() thirdpartymodule_b.sentinel = False 

बेशक, यह मौजूदा कोड को प्रभावित किए बिना इसे उचित फिक्स बनाने के लिए काफी तुच्छ है लेकिन आपको अन्य मॉड्यूल को थोड़ा बदलना होगा:

 import thirdpartymodule_a def dosomething(sentinel = False): sc = thirdpartymodule_a.SomeClass(sentinel) sc.show() 

और init पास:

 class SomeClass(object): def __init__(self, sentinel=False): if sentinel: <do my custom code> else: # Original code self.a = 42 def show(self): print self.a 

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

यहाँ एक उदाहरण है मैं Popen का उपयोग करके pytest Popen साथ आया था।

मॉड्यूल आयात करें:

 # must be at module level in order to affect the test function context from some_module import helpers 

एक MockBytes ऑब्जेक्ट:

 class MockBytes(object): all_read = [] all_write = [] all_close = [] def read(self, *args, **kwargs): # print('read', args, kwargs, dir(self)) self.all_read.append((self, args, kwargs)) def write(self, *args, **kwargs): # print('wrote', args, kwargs) self.all_write.append((self, args, kwargs)) def close(self, *args, **kwargs): # print('closed', self, args, kwargs) self.all_close.append((self, args, kwargs)) def get_all_mock_bytes(self): return self.all_read, self.all_write, self.all_close 

नकली पॉपेंस इकट्ठा करने के लिए एक MockPopen फैक्ट्री:

 def mock_popen_factory(): all_popens = [] class MockPopen(object): def __init__(self, args, stdout=None, stdin=None, stderr=None): all_popens.append(self) self.args = args self.byte_collection = MockBytes() self.stdin = self.byte_collection self.stdout = self.byte_collection self.stderr = self.byte_collection pass return MockPopen, all_popens 

और एक उदाहरण परीक्षण:

 def test_copy_file_to_docker(): MockPopen, all_opens = mock_popen_factory() helpers.Popen = MockPopen # replace builtin Popen with the MockPopen result = copy_file_to_docker('asdf', 'asdf') collected_popen = all_popens.pop() mock_read, mock_write, mock_close = collected_popen.byte_collection.get_all_mock_bytes() assert mock_read assert result.args == ['docker', 'cp', 'asdf', 'some_container:asdf'] 

यह एक समान उदाहरण है, लेकिन pytest.fixture उपयोग से यह Popen भीतर निर्मित Popen क्लास आयात को ओवरराइड कर pytest.fixture है:

 @pytest.fixture def all_popens(monkeypatch): # monkeypatch is magically injected all_popens = [] class MockPopen(object): def __init__(self, args, stdout=None, stdin=None, stderr=None): all_popens.append(self) self.args = args self.byte_collection = MockBytes() self.stdin = self.byte_collection self.stdout = self.byte_collection self.stderr = self.byte_collection pass monkeypatch.setattr(helpers, 'Popen', MockPopen) return all_popens def test_copy_file_to_docker(all_popens): result = copy_file_to_docker('asdf', 'asdf') collected_popen = all_popens.pop() mock_read, mock_write, mock_close = collected_popen.byte_collection.get_all_mock_bytes() assert mock_read assert result.args == ['docker', 'cp', 'asdf', 'fastload_cont:asdf']