2010-05-27 24 views
33

पाइथन में आईपीथॉन के साथ एक बड़ी परियोजना (कई फाइलों और फ़ोल्डर्स में विभाजित) विकसित करते समय, मैं कैश किए गए आयातित मॉड्यूल की परेशानी में भाग लेता हूं।आयातित मॉड्यूल को कैशिंग करने से पाइथन को रोकें

समस्या यह है कि निर्देश import module केवल मॉड्यूल को बदलता है, भले ही वह मॉड्यूल बदल गया हो! इसलिए हर बार जब मैं अपने पैकेज में कुछ बदलता हूं, तो मुझे आईपीथन छोड़ना और पुनरारंभ करना होगा। दर्दनाक।

क्या कुछ मॉड्यूल को पुनः लोड करने के लिए सही तरीके से बल देने का कोई तरीका है? या, बेहतर, किसी भी तरह से पाइथन उन्हें कैशिंग से रोकने के लिए?

मैंने कई दृष्टिकोणों की कोशिश की, लेकिन कोई भी काम नहीं करता है। विशेष रूप से मैं वास्तव में अजीब बग्स चलाता हूं, जैसे कि कुछ मॉड्यूल या वेरिएबल्स रहस्यमय रूप से None के बराबर बन रहे हैं ...

मुझे पाया गया एकमात्र समझदार संसाधन Reloading Python modules है, लेकिन मैंने इसे चेक नहीं किया है। मुझे ऐसा कुछ चाहिए।

आईपीथॉन को पुनरारंभ करने के लिए एक अच्छा विकल्प होगा, या किसी भी तरह पाइथन दुभाषिया को पुनरारंभ करें।

तो, यदि आप पाइथन में विकसित होते हैं, तो आपको इस समस्या का क्या समाधान मिला है?

संपादित

बातें स्पष्ट करने के लिए: जाहिर है, मैं समझता हूँ कि कुछ पुराने मॉड्यूल के पहले वाली स्थिति पर निर्भर करता है चर पर रुकने सकता है। मेरी तरफ से ठीक है। पाइथन में इतनी मुश्किल क्यों है कि बिना किसी अजीब त्रुटियों के एक मॉड्यूल को फिर से लोड किया जाए?

अधिक विशेष रूप से, अगर मैं में एक फ़ाइल module.py मेरे पूरे मॉड्यूल है उसके बाद निम्न ठीक काम करता है:

import sys 
try: 
    del sys.modules['module'] 
except AttributeError: 
    pass 
import module 

obj = module.my_class() 

कोड का यह टुकड़ा खूबसूरती से काम करता है और मैं महीनों के लिए IPython छोड़ने के बिना विकसित कर सकते हैं।

हालांकि, जब भी अपने मॉड्यूल कई submodules से बना है, नरक टूट ढीला:

import os 
for mod in ['module.submod1', 'module.submod2']: 
    try: 
     del sys.module[mod] 
    except AttributeError: 
     pass 
# sometimes this works, sometimes not. WHY? 

क्यों है कि क्या मैं एक बड़ी फ़ाइल में या कई submodules में मेरी मॉड्यूल है अजगर के लिए कि क्यों भिन्न है? वह दृष्टिकोण क्यों काम नहीं करेगा ??

+0

यह वास्तव में एक बहुत लोकप्रिय सवाल है; हर महीने पॉप अप करें। माइक ने बताया कि वर्तमान सर्वसम्मति आपके दुभाषिया को पुनरारंभ करना है। –

+2

सबसे पहले, मैं नहीं देख सकता कि आप _AttributeError_ को दबाने क्यों कर रहे हैं। वहां कोई रास्ता नहीं है 'del sys.modules [mod] 'एट्रिब्यूट एरर बढ़ाएगा ... सिवाय इसके कि यदि आप बिल्टिन sys मॉड्यूल के अलावा किसी अन्य चीज़ को' sys' को रीबाउंड करते हैं। क्या यह बस दूसरे कोड में हो सकता है, आपके पास 'sys.module' है (जो _will_ सामान्य sys के साथ विशेषता Error बढ़ाता है), और पहले, आपके पास' sys.modules' है? :- पी – Veky

उत्तर

8

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

+4

अंधविश्वास! हॉट रीलोडिंग अपेक्षाकृत सुन्दर रूप से यहां तक ​​कि [सामान्य रूप से] Pyunit] (http://pyunit.sourceforge.net/notes/reloading.html) में भी प्राप्त की जाती है, लेकिन विशिष्ट मामलों में इसे स्थापित करने में लंबा समय नहीं लगता है और बहुत भुगतान करता है कुंआ। उदाहरण के लिए, मेरी योजना में एक हल्का मुख्य मॉड्यूल होता है जिसमें एक सिंगलटन होता है जो मेरे सभी अन्य उदाहरण लटकते हैं, और केवल उनके तरीकों को कॉल करते हैं, कार्यों में नहीं। रीलोडिंग प्रत्येक I के लिए है: del sys.modules [mymodule_i] ', 'पुनः लोड करें (..)' उन्हें ',' प्रत्येक उदाहरण के' __class__' को पुराने से नए में बदलना। –

+3

डिबगेबल, समझने योग्य कोड सादा और सरल है। इस तरह जटिलता जोड़ना समझदार या उचित नहीं है। मैं इस तरह के रूप में कहीं भी दूरस्थ रूप से कुछ भी करने की सिफारिश नहीं करता। –

+0

शायद छोड़कर यदि लक्ष्य वातावरण को आसानी से पुनरारंभ नहीं किया जा सकता है। उदाहरण के लिए, ब्लेंडर को दुभाषिया स्थिति को साफ़ करने के लिए एक एप्लिकेशन को पुनरारंभ करने की आवश्यकता होती है जो ऐड-ऑन को ऑन-ऑन प्राप्त करने के लिए भयानक उपयोगकर्ता अनुभव है (ऐड-ऑन यूआई इसे अनुमति देता है) यदि ऐड-ऑन एक मॉड्यूल से बड़ा है। – Coburn

21

import यह देखने के लिए जांच करता है कि मॉड्यूल sys.modules में है, और यदि ऐसा है, तो यह इसे वापस कर देता है। यदि आप डिस्क से ताजा मॉड्यूल लोड करने के लिए आयात करना चाहते हैं, तो आप sys.modules में उपयुक्त कुंजी को हटा सकते हैं।

reload बिल्टिन फ़ंक्शन है जो मॉड्यूल ऑब्जेक्ट दिया जाएगा, इसे डिस्क से पुनः लोड करेगा और इसे sys.modules में रखा जाएगा। संपादित करें - असल में, यह डिस्क पर फ़ाइल से कोड को पुन: संकलित करेगा, और फिर मौजूदा मॉड्यूल के __dict__ में इसे फिर से evalute।एक नया मॉड्यूल ऑब्जेक्ट बनाने से कुछ संभावित रूप से बहुत अलग है।

माइक ग्राहम सही है; यदि आपके पास कुछ लाइव ऑब्जेक्ट्स हैं जो मॉड्यूल की सामग्री को संदर्भित करते हैं, तो आप फिर से लोड करना सही नहीं कर रहे हैं। मौजूदा ऑब्जेक्ट्स अभी भी उन कक्षाओं का संदर्भ देंगे जिन्हें वे तत्काल जारी कर चुके थे, एक स्पष्ट मुद्दा है, लेकिन from module import symbol के माध्यम से बनाए गए सभी संदर्भ मॉड्यूल के पुराने संस्करण से जो भी ऑब्जेक्ट इंगित करेंगे। बहुत कम गलत चीजें संभव हैं।

संपादित करें: मैं सर्वसम्मति से सहमत हूं कि दुभाषिया को पुनरारंभ करना अब तक की सबसे विश्वसनीय चीज़ है। लेकिन डिबगिंग उद्देश्यों के लिए, मुझे लगता है कि आप निम्न की तरह कुछ कोशिश कर सकते हैं। मुझे यकीन है कि ऐसे कोने के मामले हैं जिनके लिए यह काम नहीं करेगा, लेकिन यदि आप कुछ भी पागल नहीं कर रहे हैं (अन्यथा) मॉड्यूल लोडिंग के साथ में पैकेज, यह उपयोगी हो सकता है।

def reload_package(root_module): 
    package_name = root_module.__name__ 

    # get a reference to each loaded module 
    loaded_package_modules = dict([ 
     (key, value) for key, value in sys.modules.items() 
     if key.startswith(package_name) and isinstance(value, types.ModuleType)]) 

    # delete references to these loaded modules from sys.modules 
    for key in loaded_package_modules: 
     del sys.modules[key] 

    # load each of the modules again; 
    # make old modules share state with new modules 
    for key in loaded_package_modules: 
     print 'loading %s' % key 
     newmodule = __import__(key) 
     oldmodule = loaded_package_modules[key] 
     oldmodule.__dict__.clear() 
     oldmodule.__dict__.update(newmodule.__dict__) 

कौन सा मैं बहुत संक्षेप में इतना तरह का परीक्षण किया:

import email, email.mime, email.mime.application 
reload_package(email) 

मुद्रण:

reloading email.iterators 
reloading email.mime 
reloading email.quoprimime 
reloading email.encoders 
reloading email.errors 
reloading email 
reloading email.charset 
reloading email.mime.application 
reloading email._parseaddr 
reloading email.utils 
reloading email.mime.base 
reloading email.message 
reloading email.mime.nonmultipart 
reloading email.base64mime 
+3

मैंने 'sys.modules' में उचित प्रविष्टि को हटाकर और 'रीलोड' का उपयोग करके उन दृष्टिकोणों की कोशिश की। यह कभी-कभी काम करता है, लेकिन कभी-कभी बहुत, बहुत सूक्ष्म और अजीब बग बनाते हैं, जहां कुछ चर अचानक किसी भी कारण से 'कोई नहीं' बन जाते हैं। –

+3

"चिकित्सक, जब मैं इस तरह जाता हूं तो दर्द होता है", "ठीक है, ऐसा मत करो"। मैंने हमेशा डीबगिंग करते समय 'रीलोड' को केवल एक सुविधा के रूप में देखा है और इसे एक दस्तावेज बग लगता है जिसे वास्तविक लाइव लोडिंग के लिए निर्धारित किया गया है, यह बताता है कि यह अर्थपूर्ण त्रुटियों को कितना खराब हो सकता है। – msw

+0

मुझे आपके परिदृश्य के लिए उपयोगी आपके उत्तर की 'del sys.modules [key]' पंक्ति मिली। मैं मानता हूं कि यह प्रश्न पूछने के रूप में कैशिंग को रोकता नहीं है, लेकिन ये कार्य समय-समय पर पाइथन कैश की अवधि समाप्त करने जैसे व्यवहार को बनाने में मदद कर सकते हैं। –

2

आप आयात हुक मशीनरी PEP 302 में वर्णित का उपयोग कर सकते themself लेकिन प्रॉक्सी किसी तरह का मॉड्यूल नहीं लोड करने के लिए ऑब्जेक्ट जो आपको अंतर्निहित मॉड्यूल ऑब्जेक्ट के साथ कुछ भी करने की अनुमति देगा - इसे पुनः लोड करें, इसके संदर्भ में ड्रॉप करें।

अतिरिक्त लाभ यह है कि आपके वर्तमान में मौजूदा कोड को परिवर्तन की आवश्यकता नहीं होगी और इस अतिरिक्त मॉड्यूल कार्यक्षमता को कोड में एक बिंदु से फेंक दिया जा सकता है - जहां आप वास्तव में sys.meta_path में खोजक जोड़ते हैं।

लागू करने पर कुछ विचार: खोजक कि builtin (आप अंतर्निहित मॉड्यूल के साथ कोई लेना देना नहीं है), तो लोडर कि प्रॉक्सी वस्तु types.ModuleType के बजाय वास्तविक मॉड्यूल वस्तु से subclassed वापस आ जाएगी बनाने के अलावा, किसी भी मॉड्यूल को खोजने के लिए सहमत होंगे पैदा करते हैं। ध्यान दें कि लोडर ऑब्जेक्ट को sys.modules में लोड मॉड्यूल के स्पष्ट संदर्भ बनाने के लिए मजबूर नहीं किया जाता है, लेकिन इसे दृढ़ता से प्रोत्साहित किया जाता है, क्योंकि, जैसा कि आपने पहले ही देखा है, यह अप्रत्याशित रूप से विफल हो सकता है। प्रॉक्सी ऑब्जेक्ट को संदर्भित रखने वाले वास्तविक मॉड्यूल के लिए सभी __getattr__, __setattr__ और __delattr__ को पकड़ना और आगे बढ़ाना चाहिए। आपको शायद __getattribute__ को परिभाषित करने की आवश्यकता नहीं होगी क्योंकि आप अपने प्रॉक्सी विधियों के साथ वास्तविक मॉड्यूल सामग्री को छिपा नहीं पाएंगे। तो, अब आपको किसी भी तरह से प्रॉक्सी के साथ संवाद करना चाहिए - आप अंतर्निहित संदर्भ को छोड़ने के लिए कुछ विशेष विधि बना सकते हैं, फिर मॉड्यूल आयात कर सकते हैं, लौटा प्रॉक्सी से संदर्भ निकालें, प्रॉक्सी ड्रॉप करें और पुनः लोड मॉड्यूल के संदर्भ को दबाएं। पुhew, डरावना दिखता है, लेकिन हर बार पाइथन को पुनः लोड किए बिना आपकी समस्या को ठीक करना चाहिए।

7

आईपीथॉन autoreload extension आता है जो स्वचालित रूप से प्रत्येक फ़ंक्शन कॉल से पहले एक आयात दोहराता है। यह कम से कम सरल मामलों में काम करता है, लेकिन इस पर अधिक भरोसा न करें: मेरे अनुभव में, समय-समय पर एक दुभाषिया पुनरारंभ करना आवश्यक है, खासकर जब कोड परिवर्तन केवल अप्रत्यक्ष रूप से आयातित कोड पर होते हैं। लिंक किए गए पृष्ठ से

प्रयोग उदाहरण:

In [1]: %load_ext autoreload 

In [2]: %autoreload 2 

In [3]: from foo import some_function 

In [4]: some_function() 
Out[4]: 42 

In [5]: # open foo.py in an editor and change some_function to return 43 

In [6]: some_function() 
Out[6]: 43 
+1

मैंने पाया कि गहरा पदानुक्रम होने पर '% autoreload 2' काम नहीं करता है, यह समाधान हमेशा काम करता है: http: //stackoverflow.com/a/13096672/311567 जो मुझे आशा है कि आईपीथॉन – dashesy

3

वास्तव में कुछ अच्छे जवाब पहले से ही यहाँ कर रहे हैं, लेकिन यह dreload, एक समारोह IPython में उपलब्ध है जो "गहरी पुनः लोड" के रूप में करता है जिसके बारे में जानने लायक है। प्रलेखन से:

IPython.lib।deepreload मॉड्यूल आपको मॉड्यूल को दोबारा लोड करने की अनुमति देता है: इसकी किसी भी निर्भरता में किए गए परिवर्तनों को बाहर निकलने के बिना को पुनः लोड किया जाएगा। इसे का उपयोग शुरू करने के लिए, कार्य करें:

http://ipython.org/ipython-doc/dev/interactive/reference.html#dreload

यह एक "वैश्विक" IPython नोटबुक में (कम से कम मेरी संस्करण है, जो v2.0 चल रहा है) के रूप में उपलब्ध है।

HTH

2

मैं अपने प्रोजेक्ट में PythonNet उपयोग कर रहा हूँ। सौभाग्य से, मैंने पाया कि एक आदेश है जो इस समस्या को पूरी तरह से हल कर सकता है।

using (Py.GIL()) 
     { 
      dynamic mod = Py.Import(this.moduleName); 
      if (mod == null) 
       throw new Exception(string.Format("Cannot find module {0}. Python script may not be complied successfully or module name is illegal.", this.moduleName)); 

      // This command works perfect for me! 
      PythonEngine.ReloadModule(mod); 

      dynamic instance = mod.ClassName(); 
+1

में डिफ़ॉल्ट हो जाएगा मुझे विश्वास है कि प्रश्न पायथन दुभाषिया को पुनरारंभ करने के बारे में है। आप इसके भीतर सी # और पायथन इंजन का उपयोग कर रहे हैं। ? Proabaly नहीं ओपी क्या देख रहा है। – Vasif

+0

@ user7175781 वाक्यविन्यास मेरे सिस्टम पर काम नहीं कर रहा है इससे कोई फर्क नहीं पड़ता कि मैं क्या प्रयास करता हूं। मुझे लगता है कि PythonNet ipython की तुलना में अलग वाक्यविन्यास और एपीआई है। मैं काम करने के लिए आपका उदाहरण प्राप्त करने की उम्मीद कर रहा था लेकिन दुभाषिया द्वारा रिपोर्ट की गई कई त्रुटियों के बाद मुझे अंततः एहसास हुआ कि आपने पाइथननेट भाषा कहा है। –

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