यह सब स्थिति पर निर्भर करता है। उदाहरण के लिए, यदि आप परीक्षण प्रयोजनों के लिए निर्भरता इंजेक्शन का उपयोग करें - ताकि आप आसानी से बाहर कुछ नकली कर सकते हैं - आप अक्सर पूरी तरह इंजेक्शन छोड़ कर सकते हैं:
subprocess.Popen = some_mock_Popen
result = subprocess.call(...)
assert some_mock_popen.result == result
: आप के बजाय मॉड्यूल या वर्ग आप अन्यथा डालेगी बाहर नकली कर सकते हैं subprocess.call()
subprocess.Popen()
पर कॉल करेगा, और हम किसी विशेष तरीके से निर्भरता को इंजेक्ट किए बिना इसे नकल कर सकते हैं। हम सीधे subprocess.Popen
को प्रतिस्थापित कर सकते हैं। (यह केवल एक उदाहरण है; वास्तविक जीवन में आप इसे अधिक मजबूत तरीके से करेंगे।)
यदि आप अधिक जटिल स्थितियों के लिए निर्भरता इंजेक्शन का उपयोग करते हैं, या जब पूरे मॉड्यूल या कक्षाओं का मज़ाक उड़ाते हैं तो उचित नहीं है (क्योंकि, उदाहरण के लिए, आप केवल एक विशेष कॉल को मजाक करना चाहते हैं) फिर निर्भरता के लिए कक्षा विशेषताओं या मॉड्यूल ग्लोबल्स का उपयोग करना सामान्य विकल्प है। उदाहरण के लिए, पर विचार एक my_subprocess.py
:
from subprocess import Popen
def my_call(...):
return Popen(...).communicate()
आप आसानी से केवल Popen
कॉल my_subprocess.Popen
को बताए द्वारा my_call()
द्वारा बनाई गई जगह ले सकता है; यह subprocess.Popen
के लिए किसी भी अन्य कॉल प्रभाव पड़ेगा (लेकिन यह निश्चित रूप से, my_subprocess.Popen
के लिए सभी कॉल की जगह लेंगे।) इसी प्रकार, वर्ग जिम्मेदार बताते हैं:
class MyClass(object):
Popen = staticmethod(subprocess.Popen)
def call(self):
return self.Popen(...).communicate(...)
वर्ग का उपयोग कर इस तरह जिम्मेदार बताते है, जो शायद ही कभी आवश्यक विकल्पों पर विचार कर रहा है , आपको staticmethod
का उपयोग करने की देखभाल करनी चाहिए। यदि आप नहीं करते हैं, और जिस वस्तु को आप सम्मिलित कर रहे हैं वह एक सामान्य फ़ंक्शन ऑब्जेक्ट या किसी अन्य प्रकार का वर्णनकर्ता है, जैसे किसी संपत्ति या, किसी वर्ग या उदाहरण से पुनर्प्राप्त होने पर कुछ खास करता है, तो यह गलत काम करेगा। इससे भी बदतर, अगर आपने का उपयोग किया है तो अभी एक वर्णक नहीं है (उदाहरण के लिए subprocess.Popen
वर्ग की तरह) यह अब काम करेगा, लेकिन यदि प्रश्न में वस्तु सामान्य कार्य में बदल गई है, तो यह भ्रमित हो जाएगा।
आखिरकार, केवल सादे कॉलबैक हैं; अगर आप सिर्फ किसी विशेष सेवा के लिए एक वर्ग का एक विशेष उदाहरण टाई करना चाहते हैं, तो आप सिर्फ वर्ग प्रारंभकर्ता को सेवा (या एक या एक से सेवा की विधियों का) पारित कर सकते हैं, और यह है कि का उपयोग करें:
class MyClass(object):
def __init__(self, authenticate=None, authorize=None):
if authenticate is None:
authenticate = default_authenticate
if authorize is None:
authorize = default_authorize
self.authenticate = authenticate
self.authorize = authorize
def request(self, user, password, action):
self.authenticate(user, password)
self.authorize(user, action)
self._do_request(action)
...
helper = AuthService(...)
# Pass bound methods to helper.authenticate and helper.authorize to MyClass.
inst = MyClass(authenticate=helper.authenticate, authorize=helper.authorize)
inst.request(...)
इस तरह के आवृत्ति गुणों को सेट करते समय, आपको कभी भी वर्णक फायरिंग के बारे में चिंता करने की ज़रूरत नहीं है, इसलिए केवल कार्य (या कक्षाएं या अन्य कॉलबेल या उदाहरण) असाइन करना ठीक है।
मेरे पास सी # पृष्ठभूमि है इसलिए मुझे कन्स्ट्रक्टर के माध्यम से स्पष्ट इंजेक्शन और सब कुछ हल करने के लिए कंटेनर का उपयोग करने के लिए उपयोग किया जाता है। प्रारंभकर्ता में किसी को भी डिफ़ॉल्ट निर्दिष्ट करना "गरीब आदमी की डी" जैसा दिखता है जो मेरे लिए सबसे अच्छा अभ्यास नहीं दिखता क्योंकि यह पर्याप्त स्पष्ट नहीं है। असाइनमेंट द्वारा मौजूदा विधियों को बदलने के बारे में समान विचार (क्या इसे 'बंदर पैचिंग' कहा जाता है?)। क्या मुझे अपनी मानसिकता बदलनी चाहिए क्योंकि पाइथन-रास्ता सी # -वे से अलग है? –
हां, यदि आप कुशल, पायथनिक कोड लिखना चाहते हैं, तो आपको यह महसूस करना चाहिए कि पायथन एक अलग भाषा है। आप अलग-अलग चीजें अलग-अलग करते हैं। परीक्षण के लिए बंदरगाह मॉड्यूल वास्तव में बहुत आम है और काफी सुरक्षित है (विशेष रूप से जब आपके लिए विवरणों को संभालने के लिए उचित मॉकिंग लाइब्रेरी का उपयोग करते हैं।) बंदरगाह वर्ग (कक्षाओं पर विशिष्ट तरीकों को बदलना) एक अलग मामला है। कोई भी डिफ़ॉल्ट वास्तव में उस चीज़ पर नहीं है जिस पर आपको ध्यान देना चाहिए - वह उदाहरण वास्तव में कन्स्ट्रक्टर के माध्यम से डी के करीब है, आप केवल डिफ़ॉल्ट को छोड़ सकते हैं और यदि आप चाहें तो इसे एक आवश्यक तर्क बना सकते हैं। –
@ थॉमसवाउटर आप इसे समझा सकते हैं: _ आप my_subprocess.Popen._ को असाइन करके my_call() द्वारा बनाए गए केवल पॉपन कॉल को आसानी से प्रतिस्थापित कर सकते हैं क्या आपका मतलब है कि 'subprocess.call'' subprocess.Popen' पर कॉल का आह्वान करता है? –