2013-03-07 15 views
9

मेरे पास एक कोडबेस है जहां मैं पिछले डेवलपर द्वारा कुछ गन्दा निर्णय साफ कर रहा हूं।मॉड्यूल आयात से उलट *

from scipy import * 
from numpy import * 

... यह, ज़ाहिर है, नाम स्थान को प्रदूषित करता है और यह मुश्किल बताने के लिए जहां मॉड्यूल में एक विशेषता मूल रूप से बनाता है: अक्सर, वह कुछ ऐसा किया है।

क्या Python का विश्लेषण करने और मेरे लिए इसे ठीक करने का कोई तरीका है? क्या किसी ने इसके लिए उपयोगिता की है? यदि नहीं, तो इस तरह की उपयोगिता कैसे बनाई जा सकती है?

+1

मैं तुम्हारे लिए लग रहा है यहाँ कोड का विशेष रूप से दिलचस्प हिस्सा है। आशा है कि आपको कुछ अच्छा टूल मिल जाएगा। (+1) – NPE

+0

इससे भी बेहतर, मुझे आशा है कि आप एक अच्छा टूल लिखेंगे (चाहे मेरे उत्तर पर आधारित हों या नहीं) और इसे पीपीपीआई पर प्रकाशित करें ताकि अगर मुझे कभी ऐसी चीज चाहिए तो मुझे इसे खुद करने की ज़रूरत नहीं है। :) – abarnert

+0

यह प्रश्न भी देखें: [क्या मानक मॉड्यूल का उपयोग करने के लिए पाइथन * आयात को दोबारा करने के लिए कोई आईडीई/उपयोगिता है। मेम्बर सिंटैक्स?] (Http://stackoverflow.com/questions/12677061/is-there-an-ide- उपयोगिता-से-रिफैक्टर-पायथन-आयात-से-उपयोग-मानक-मॉड्यूल-memb) –

उत्तर

0

अब मैंने ऐसा करने के लिए एक छोटी उपयोगिता बनाई है जिसे मैं 'dedazzler' कहता हूं। यह उन पंक्तियों को मिलेगा जो 'मॉड्यूल आयात *' से हैं, और फिर लाइनों को प्रतिस्थापित करते हुए लक्षित मॉड्यूल के 'डीआईआर' का विस्तार करें।

इसे चलाने के बाद, आपको अभी भी एक लिटर चलाने की आवश्यकता है।

import re 

star_match = re.compile('from\s(?P<module>[\.\w]+)\simport\s[*]') 
now = str(time.time()) 
error = lambda x: sys.stderr.write(x + '\n') 

def replace_imports(lines): 
    """ 
    Iterates through lines in a Python file, looks for 'from module import *' 
    statements, and attempts to fix them. 
    """ 
    for line_num, line in enumerate(lines): 
     match = star_match.search(line) 
     if match: 
      newline = import_generator(match.groupdict()['module']) 
      if newline: 
       lines[line_num] = newline 
    return lines 

def import_generator(modulename): 
    try: 
     prop_depth = modulename.split('.')[1:] 
     namespace = __import__(modulename) 
     for prop in prop_depth: 
      namespace = getattr(namespace, prop) 
    except ImportError: 
     error("Couldn't import module '%s'!" % modulename) 
     return 
    directory = [ name for name in dir(namespace) if not name.startswith('_') ] 
    return "from %s import %s\n"% (modulename, ', '.join(directory)) 

मैं एक और अधिक उपयोगी स्टैंड-अलोन उपयोगिता प्रपत्र यहाँ में इस को बनाए रखने कर रहा हूँ:

https://github.com/USGM/dedazzler/

-1

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

संपादित करने के लिए किसी टूल के बारे में पता है तो मुझे खुशी होगीरान होगा: आह हाँ, एक लिटर, मैंने इसके बारे में सोचा नहीं था।

3

हां। आयात हटाएं और मॉड्यूल पर एक लिटर चलाएं।

मैं flake8 का उपयोग करने की सलाह देता हूं, हालांकि यह शैली त्रुटियों के बारे में बहुत शोर भी बना सकता है।

केवल आयात को हटाने और कोड चलाने की कोशिश करने के लिए संभवतः पर्याप्त नहीं होने वाला है, क्योंकि कई नाम त्रुटियां तब तक नहीं उठाई जाएंगी जब तक आप केवल सही इनपुट के साथ कोड की सही रेखा नहीं चलाते। एक लिटर इसके बजाय पार्सिंग द्वारा कोड का विश्लेषण करेगा और कोड चलाने के बिना संभावित NameError एस का पता लगाएगा।

यह सब मानता है कि कोई विश्वसनीय इकाई परीक्षण नहीं है, या परीक्षण पर्याप्त कवरेज प्रदान नहीं करते हैं।

इस मामले में, जहां कईfrom module import * लाइनों देखते हैं, यह एक छोटे से अधिक है कि में दर्दनाक आप प्रत्येक और हर लापता नाम के लिए यह पता लगाने की जरूरत है हो जाता है क्या मॉड्यूल की आपूर्ति की है कि नाम। यही कारण है कि शारीरिक श्रम की आवश्यकता होगी, लेकिन आप बस एक अजगर दुभाषिया और परीक्षण में मॉड्यूल आयात कर सकते हैं लापता ऐसा नाम है जो मॉड्यूल पर परिभाषित किया गया है:

>>> import scipy, numpy 
>>> 'loadtxt' in dir(numpy) 
True 

आप को ध्यान में रखना करने की आवश्यकता है कि इस विशिष्ट मामले में, कि numpy और scipy मॉड्यूल के बीच ओवरलैप है; दोनों मॉड्यूल में परिभाषित किसी भी नाम के लिए, मॉड्यूल ने आखिरी जीत आयात की।

ध्यान दें कि from module import * जगह पर लाइन का मतलब है कि लिटर का पता लगाने में सक्षम नहीं होगा कि नाम क्या नाम उठा सकते हैं नाम!

+0

यदि मैं आयात को हटा देता हूं, तो यह मुझे कैसे बताएगा कि कौन से मॉड्यूल नाम हैं? क्या यह उन सभी विशेषताओं पर सिर्फ आतंकवादी नहीं होगा जो अब असूचीबद्ध हैं? – Kelketek

+0

@ केल्केक: हाँ, और आपको प्रत्येक के लिए यह पता लगाना होगा कि यह किस मॉड्यूल से है * माना जाता है। वह मुश्किल नहीं है, सौभाग्य से। –

+0

यदि आप उन्हें एक समय में हटाते हैं, तो यह संभवतः आसान है। – geoffspear

3

मुझे लगता है कि प्योरिटीलेक और मार्टिजन पीटर के सहायक मैनुअल समाधान शायद जाने का सबसे अच्छा तरीका हैं। लेकिन यह प्रोग्रामेटिक रूप से करने के लिए असंभव नहीं है।

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

संभालने हूँ, आप उन के माध्यम से पुनरावृति करने के लिए, पता लगाने के लिए जो मॉड्यूल प्रत्येक वस्तु के मूल रूप में परिभाषित किया गया था inspect.getmodule() का उपयोग कर की जरूरत है। और मैं कर रहा हूँ यह मानते हुए कि आप किसी भी चीज का उपयोग नहीं कर रहे हैं जो दोगुनी from foo import * -ed है।numpy और scipy मॉड्यूल में परिभाषित सभी नामों की एक सूची बनाएं।

अब आप उस आउटपुट को ले सकते हैं और प्रत्येक foo को numpy.foo के साथ प्रतिस्थापित कर सकते हैं।

इसलिए, यह एक साथ कुछ इस तरह डाल,:

for modname in sys.argv[1:]: 
    with open(modname + '.py') as srcfile: 
     src = srcfile.read() 
    src = src.replace('from numpy import *', 'import numpy') 
    src = src.replace('from scipy import *', 'import scipy') 
    mod = __import__(modname) 
    for name in dir(mod): 
     original_mod = inspect.getmodule(getattr(mod, name)) 
     if original_mod.__name__ == 'numpy': 
      src = src.replace(name, 'numpy.'+name) 
     elif original_mod.__name__ == 'scipy': 
      src = src.replace(name, 'scipy.'+name) 
    with open(modname + '.tmp') as dstfile: 
     dstfile.write(src) 
    os.rename(modname + '.py', modname + '.bak') 
    os.rename(modname + '.tmp', modname + '.py') 

हैं मान्यताओं के या तो गलत है, यह कोड को बदलने के लिए मुश्किल नहीं है। साथ ही, आप tempfile.NamedTemporaryFile और अन्य सुधारों का उपयोग यह सुनिश्चित करने के लिए कर सकते हैं कि आप अस्थायी रूप से अस्थायी फ़ाइलों के साथ चीजों को ओवरराइट न करें। (मैं बस क्रॉस-प्लेटफार्म लिखने के सिरदर्द से निपटना नहीं चाहता था; यदि आप विंडोज़ पर नहीं चल रहे हैं, तो यह आसान है।) और कुछ त्रुटि प्रबंधन, जाहिर है, और शायद कुछ रिपोर्टिंग में जोड़ें।

+0

मुझे नहीं लगता कि यह काफी काम करेगा। 'My_foo' नामक चर के बारे में क्या। अचानक आप 'my_numpy.foo' प्राप्त करते हैं। उफ़। बेशक, एक उचित पार्सर दिया गया है (मैं 'अस्थ' सोच रहा हूं), आप शायद ऐसा कर सकते हैं। – mgilson

+0

यह शायद और अधिक है जो मैं ढूंढ रहा हूं। उस व्यक्ति के पास कभी-कभी मॉड्यूल थे जहां पांच अलग वाइल्डकार्ड आयात किए गए थे। यह पागलपन है। यहां खोज और प्रतिस्थापन थोड़ा खतरनाक है, क्योंकि इससे कुछ धारणाएं होती हैं, लेकिन यह विचार मुझे सही दिशा में रखता है। – Kelketek

+0

आखिरकार, यह एक उपकरण के लिए एक उचित शुरुआत है जो पूरे समुदाय के लिए उपयोगी हो सकती है। मुझे यह भी आश्चर्य है कि इस तरह की चीज '__all__' के साथ कैसे बातचीत करेगी। इसे वास्तव में सही करने के लिए, संभवतः आप उन मॉडलों को फ़िल्टर करना चाहते हैं जो 'मॉड्यूल में नहीं हैं .__ all__' यदि यह मौजूद है। – mgilson

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