2015-09-28 7 views
6

कहते हैं कि मैं मॉड्यूल में निम्नलिखित 2 वर्ग की सुविधा देता है aपायथन: कैसे बंदर पैच (स्वैप) वर्गों के लिए

class Real(object): 
    ... 
    def print_stuff(self): 
     print 'real' 

class Fake(Real): 
    def print_stff(self): 
     print 'fake' 

मॉड्यूल b में यह Real वर्ग का उपयोग करता है

from a import Real 
Real().print_stuff() 

मैं कैसे बंदर करना पैच ताकि b आयात Real यह वास्तव में Fake के साथ बदल गया है?

मैं स्क्रिप्ट प्रारंभ करने में ऐसा करने की कोशिश कर रहा था लेकिन यह काम नहीं करता है।

if env == 'dev': 
    from a import Real, Fake 
    Real = Fake 

मेरा उद्देश्य विकास मोड में नकली कक्षा का उपयोग करना है।

+0

यह प्रारंभिक स्क्रिप्ट क्या है यह एक और '.py' है जो आपके मूल कार्यक्रम की शुरुआत में चलता है? –

+0

हां यह एक Django ऐप है, इसलिए init स्क्रिप्ट app.py में है, मैंने सामान्य होने के उद्देश्य से इसका उल्लेख नहीं किया है। –

उत्तर

2

मुद्दा यह है कि जब आप करते हैं -

from a import Real, Fake 

आप मूल रूप से अपने initialize स्क्रिप्ट के नाम स्थान में उन दो वर्गों आयात कर रहे हैं और initialize स्क्रिप्ट के नाम स्थान में Real और Fake नाम बनाने । फिर आप Realinitialize स्क्रिप्ट पॉइंट Fake पर नाम बनाते हैं, लेकिन यह वास्तविक a मॉड्यूल में कुछ भी नहीं बदलता है। initialize स्क्रिप्ट एक और .py मॉड्यूल/अपने मूल कार्यक्रम के शुरू में रन पर स्क्रिप्ट है

है, तो आप नीचे का उपयोग कर सकते हैं -

if env == 'dev': 
    import a 
    a.Real = a.Fake 

कृपया ध्यान दें, इस Fake वर्ग का उल्लेख करने के a.Real होगा जब भी आप उपरोक्त पंक्ति निष्पादित होने के बाद a मॉड्यूल से Real का उपयोग करते हैं।


हालांकि मैं सुझाव है कि एक बेहतर तरीका अपने a मॉड्यूल अपने आप में यह करने के लिए, यह संभव है कि मॉड्यूल में env जाँच करने के लिए कर रही है, के रूप में द्वारा होगा -

if <someothermodule>.env == 'dev': 
    Real = Fake 

जैसा टिप्पणियों में पूछा गया था -

स्क्रिप्ट के नामस्थान को प्रारंभ करने में भी आयात आयात नहीं करता है? मॉड्यूल और कक्षाओं के आयात के बीच क्या अंतर है?

बात यह है कि जब तुम सिर्फ वर्ग from a import class, क्या आप वास्तव में ऐसा है कि चर, class अपने मॉड्यूल नाम स्थान में बनाने (मॉड्यूल है कि आप इसे करने के लिए आयात में) का उपयोग करते हुए, उस चर को इंगित करने के बदलते आयात उस मॉड्यूल नेमस्पेस में कुछ नया मूल वर्ग को मूल मॉड्यूल-ऑब्जेक्ट में प्रभावित नहीं करता है, यह केवल उस मॉड्यूल में प्रभावित होता है जिसमें इसकी बदली गई है।

लेकिन जब आप import a करते हैं, तो आप सिर्फ मॉड्यूल a आयात कर रहे हैं (और जब तक मॉड्यूल वस्तु भी sys.modules शब्दकोश में कैश हो जाता है का आयात, इसलिए किसी भी अन्य मॉड्यूल से a के लिए किसी भी अन्य आयात sys.modules से इस कैश्ड संस्करण मिलेगा) (एक और नोट, यह है कि from a import something भी आंतरिक रूप से a आयात करता है और इसे sys.modules में कैश करता है, लेकिन मुझे उन विवरणों में शामिल नहीं होने देता है क्योंकि मुझे लगता है कि यह आवश्यक नहीं है)।

और फिर जब आप a.Real = <something> करते हैं, आप a मॉड्यूल वस्तु है, जो, वर्ग की ओर इशारा करता कुछ और करने के लिए की Real विशेषता बदल रहे हैं, यह सीधे a मॉड्यूल mutates, इसलिए परिवर्तन भी देखा जा सकता है जब मॉड्यूल a कुछ अन्य मॉड्यूल से आयात किया जाता है।

+0

यदि मैं इसे 'ए' मॉड्यूल के अंदर करता हूं, तो उसे मॉड्यूल 'ए' के ​​अंदर दफनाया जाएगा और अन्य लोगों के लिए यह समझना मुश्किल होगा कि क्या हो रहा है, क्या आप सहमत हैं? विशेष रूप से मॉड्यूल 'ए' लाइब्रेरी है। –

+0

हाँ, संभव है कि 'ए' बहुत बड़ा है, लेकिन मैं कहूंगा कि लोगों के एहसास के लिए यह कठिन होगा कि यह 'init' मॉड्यूल जो' ए' 'के साथ' ए' 'के साथ गड़बड़ कर रहा है। आइए कहें कि मैं एक नया डेवलपर हूं, मैंने कोड चलाया और देखा कि मुझे 'ए' से 'रीयल' कॉल करने का प्रयास करते समय मुझे कुछ नकली कक्षा मिल रही है, मैं 'ए' में कोड के अंदर जांच करता हूं और जहां मुझे लगता है कि 'असली' 'नकली' द्वारा ओवरराइट किया जा रहा है, मेरे लिए यह अनुमान लगाना मुश्किल होगा कि 'init' मॉड्यूल' ए.रियल 'को' ए 'फेक' में बदल रहा है। क्या आप सहमत हैं? –

+0

मैं अजगर आयात पर काफी नोब हूं, 'आयात' को 'प्रारंभिक' स्क्रिप्ट के नामस्थान में भी आयात नहीं करता है? मॉड्यूल और कक्षाओं के आयात के बीच क्या अंतर है? –

3

आप mock मॉड्यूल से patch का उपयोग कर सकते हैं। यहाँ एक उदाहरण है:

with patch('yourpackage.b.Real') as fake_real: 
    fake_real.return_value = Fake() 
    foo = b.someClass() 
    foo.somemethod() 
+0

क्या आपका कोड केवल संदर्भ के साथ काम करता है? मैं इस मामले में इकाई परीक्षण उद्देश्य के लिए पैचिंग नहीं कर रहा हूं। –

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