क्या यह अंदर के कार्यों को आयात करने के लिए पायथोनिक है?


126

पीईपी 8 कहता है:

  • आयात हमेशा फ़ाइल के शीर्ष पर, किसी भी मॉड्यूल टिप्पणियों और docstrings के बाद, और मॉड्यूल ग्लोबल्स और स्थिरांक से पहले किया जाता है।

रोके जाने पर, मैं PEP 8 का उल्लंघन करता हूं। कुछ बार मैं फ़ंक्शन के अंदर सामान आयात करता हूं। एक सामान्य नियम के रूप में, मैं ऐसा करता हूं यदि कोई आयात होता है जो केवल एक फ़ंक्शन के भीतर उपयोग किया जाता है।

कोई राय?

EDIT (कारण जो मुझे लगता है कि फ़ंक्शंस में आयात करना एक अच्छा विचार हो सकता है):

मुख्य कारण: यह कोड को स्पष्ट कर सकता है।

  • जब मैं किसी फ़ंक्शन का कोड देख रहा हूं तो मैं खुद से पूछ सकता हूं: "फ़ंक्शन / क्लास xxx क्या है?" (xxx फ़ंक्शन के अंदर उपयोग किया जा रहा है)। यदि मॉड्यूल के शीर्ष पर मेरे सभी आयात हैं, तो मुझे यह देखने के लिए वहां जाना होगा कि xxx क्या है। उपयोग करते समय यह एक समस्या का अधिक है from m import xxxm.xxxफंक्शन में देखना शायद मुझे और बताता है। इस पर निर्भर करता mहै: क्या यह एक प्रसिद्ध शीर्ष-स्तरीय मॉड्यूल / पैकेज ( import m) है? या यह एक उप-मॉड्यूल / पैकेज ( from a.b.c import m) है?
  • कुछ मामलों में उस अतिरिक्त जानकारी ("xxx क्या है?") के पास जहां xxx का उपयोग किया जाता है, फ़ंक्शन को समझना आसान बना सकता है।

2
और आप प्रदर्शन के लिए ऐसा करते हैं?
मकार्सी

4
मुझे लगता है कि यह कुछ मामलों में कोड को स्पष्ट करता है। मैं एक समारोह में आयात करते समय कच्चे प्रदर्शन की बूंदों का अनुमान लगाऊंगा (क्योंकि आयात विवरण हर बार फ़ंक्शन को निष्पादित करने के बाद निष्पादित करेगा)।
कोडपी

आप जवाब दे सकते हैं "फ़ंक्शन / वर्ग xxx क्या है?" xyz आयात abc सिंटैक्स के बजाय आयात xyz सिंटैक्स का उपयोग करके
टॉम लेन्स

1
यदि स्पष्टता एकमात्र कारक है, तो यू उस प्रभाव के लिए एक प्रासंगिक टिप्पणी भी शामिल कर सकता है। ;)
लक्ष्मण प्रसाद

5
@becomingGuru: ज़रूर, लेकिन टिप्पणियां वास्तविकता के साथ सिंक से बाहर निकल सकती हैं ...
कोडेपी

जवाबों:


88

लंबे समय से मुझे लगता है कि आप फ़ाइल के शीर्ष पर अपने अधिकांश आयात करने की सराहना करेंगे, इस तरह से आप एक नज़र में बता सकते हैं कि आपका मॉड्यूल कितना जटिल है जिसे आयात करने की आवश्यकता है।

यदि मैं किसी मौजूदा फ़ाइल में नया कोड जोड़ रहा हूँ, तो मैं आमतौर पर वह आयात करता हूँ जहाँ इसकी आवश्यकता होती है और फिर यदि कोड रहता है तो मैं आयात लाइन को फ़ाइल के शीर्ष पर ले जाकर चीजों को और अधिक स्थायी बना दूँगा।

एक अन्य बिंदु, मैं एक प्राप्त करना पसंद करता हूं ImportError किसी भी कोड को चलाने से पहले अपवाद - एक पवित्रता की जांच के रूप में, इसलिए यह शीर्ष पर आयात करने का एक और कारण है।

मैं pyCheckerअप्रयुक्त मॉड्यूल की जांच करने के लिए उपयोग करता हूं ।


47

ऐसे दो अवसर हैं जहां मैं इस संबंध में पीईपी 8 का उल्लंघन करता हूं:

  • परिपत्र आयात: मॉड्यूल एक मॉड्यूल बी आयात करता है, लेकिन मॉड्यूल बी में कुछ को मॉड्यूल ए की आवश्यकता होती है (हालांकि यह अक्सर एक संकेत है कि मुझे परिपत्र निर्भरता को खत्म करने के लिए मॉड्यूल को रिफैक्ट करने की आवश्यकता है)
  • Pdb ब्रेकपॉइंट सम्मिलित करना: import pdb; pdb.set_trace()यह आसान बी / सी है import pdbजिसे मैं हर मॉड्यूल के शीर्ष पर रखना नहीं चाहता जिसे मैं डिबग करना चाहता हूं, और जब मैं ब्रेकपॉइंट हटाता हूं तो आयात को याद रखना आसान है।

इन दो मामलों के बाहर, सब कुछ शीर्ष पर रखना एक अच्छा विचार है। यह निर्भरताओं को स्पष्ट करता है।


7
मैं सहमत हूं कि यह निर्भरता को समग्र रूप से मॉड्यूल के संबंध में स्पष्ट करता है। लेकिन मेरा मानना ​​है कि यह शीर्ष स्तर पर सब कुछ आयात करने के लिए फ़ंक्शन स्तर पर कोड को कम स्पष्ट कर सकता है। जब आप किसी फ़ंक्शन के कोड को देख रहे हों, तो आप स्वयं से पूछ सकते हैं: "फ़ंक्शन / क्लास xxx क्या है?" (xxx फ़ंक्शन के अंदर उपयोग किया जाता है)। और आपको यह देखने के लिए फ़ाइल के शीर्ष पर देखना होगा कि xxx कहां से आता है। यह m आयात xxx से उपयोग करते समय एक समस्या का अधिक है। M.xxx देखना आपको अधिक बताता है - कम से कम अगर कोई संदेह नहीं है कि एम क्या है।
कोडपे

20

यहां चार आयात उपयोग के मामले हैं जो हम उपयोग करते हैं

  1. import(और from x import yऔर import x as y) शीर्ष पर

  2. आयात के लिए विकल्प। शीर्ष पर।

    import settings
    if setting.something:
        import this as foo
    else:
        import that as foo
  3. सशर्त आयात। JSON, XML पुस्तकालयों और पसंद के साथ उपयोग किया जाता है। शीर्ष पर।

    try:
        import this as foo
    except ImportError:
        import that as foo
  4. गतिशील आयात। अब तक, हमारे पास इसका केवल एक उदाहरण है।

    import settings
    module_stuff = {}
    module= __import__( settings.some_module, module_stuff )
    x = module_stuff['x']

    ध्यान दें कि यह गतिशील आयात कोड में नहीं लाता है, लेकिन पायथन में लिखित जटिल डेटा संरचनाओं में लाता है। यह डेटा के एक टुकड़े की तरह है, सिवाय इसके कि हम इसे हाथ से उठाएं।

    यह भी, एक मॉड्यूल के शीर्ष पर, कम-से-कम है


यहाँ हम कोड को स्पष्ट करने के लिए क्या करते हैं:

  • मॉड्यूल कम रखें।

  • यदि मेरे पास मॉड्यूल के शीर्ष पर मेरे सभी आयात हैं, तो मुझे यह देखने के लिए वहां जाना होगा कि एक नाम क्या है। यदि मॉड्यूल छोटा है, तो यह करना आसान है।

  • कुछ मामलों में, जहां एक नाम का उपयोग किया जाता है, उसके करीब अतिरिक्त जानकारी फ़ंक्शन को समझने में आसान बना सकती है। यदि मॉड्यूल छोटा है, तो यह करना आसान है।


मॉड्यूल को छोटा रखना निश्चित रूप से एक बहुत अच्छा विचार है। लेकिन उपलब्ध कार्यों के लिए हमेशा "आयात जानकारी" होने का लाभ प्राप्त करने के लिए, अधिकतम मॉड्यूल की लंबाई एक स्क्रीन (शायद 100 रेखाएं अधिकतम) होनी चाहिए। और यह कि ज्यादातर मामलों में व्यावहारिक होना बहुत कम होगा।
कोडपे

मुझे लगता है कि आप इसे एक तार्किक चरम पर ले जा सकते हैं। मुझे लगता है कि एक संतुलन बिंदु हो सकता है जहां आपका मॉड्यूल "छोटा पर्याप्त" है जिसे आपको जटिलता के प्रबंधन के लिए फैंसी आयात तकनीक की आवश्यकता नहीं है। हमारा औसत मॉड्यूल आकार है - संयोग से - लगभग 100 लाइनें।
एस.लॉट

8

एक बात को ध्यान में रखें: अनावश्यक आयात प्रदर्शन समस्याओं का कारण बन सकता है। इसलिए यदि यह एक फ़ंक्शन है जिसे अक्सर कहा जाएगा, तो आप आयात को शीर्ष पर रखना बेहतर होगा। बेशक यह है एक अनुकूलन एक वैध मामला नहीं है, इसलिए यदि किए जाने के लिए है कि एक समारोह के अंदर का आयात एक फ़ाइल के शीर्ष पर आयात करने की तुलना में अधिक स्पष्ट है, यह है कि तुरुप ज्यादातर मामलों में प्रदर्शन।

यदि आप आयरनपाइथन कर रहे हैं, तो मुझे बताया गया है कि यह फ़ंक्शंस के अंदर आयात करना बेहतर है (क्योंकि आयरनपाइथन में कोड को धीमा किया जा सकता है)। इस प्रकार, आप तब अंदर के कार्यों को आयात करने का एक तरीका प्राप्त करने में सक्षम हो सकते हैं। लेकिन इसके अलावा, मैं तर्क दूंगा कि यह सिर्फ सम्मेलन लड़ने के लिए इसके लायक नहीं है।

एक सामान्य नियम के रूप में, मैं ऐसा करता हूं यदि कोई आयात होता है जो केवल एक फ़ंक्शन के भीतर उपयोग किया जाता है।

मैं एक और बात करना चाहूंगा कि यह एक संभावित मुख्य समस्या हो सकती है। यदि आप किसी ऐसे फ़ंक्शन को जोड़ते हैं जो केवल एक फ़ंक्शन द्वारा उपयोग किए गए मॉड्यूल का उपयोग करता है? क्या आप फ़ाइल के शीर्ष पर आयात जोड़ने के लिए याद रखने जा रहे हैं? या आप आयात के लिए प्रत्येक फ़ंक्शन को स्कैन करने जा रहे हैं?

एफडब्ल्यूआईडब्ल्यू, ऐसे मामले हैं जहां यह एक फ़ंक्शन के अंदर आयात करने के लिए समझ में आता है। उदाहरण के लिए, यदि आप भाषा को cx_Oracle में सेट करना चाहते हैं, तो आयात होने से पहले आपको NLS _LANG वातावरण चर सेट करना होगा । इस प्रकार, आप इस तरह कोड देख सकते हैं:

import os

oracle = None

def InitializeOracle(lang):
    global oracle
    os.environ['NLS_LANG'] = lang
    import cx_Oracle
    oracle = cx_Oracle

2
मैं आपके मुख्य मुद्दे से सहमत हूं। Refactoring कोड थोड़ा समस्याग्रस्त हो सकता है। यदि मैं एक दूसरे फ़ंक्शन को जोड़ता हूं जो पहले केवल एक फ़ंक्शन द्वारा उपयोग किए गए मॉड्यूल का उपयोग करता है - मैं या तो आयात को शीर्ष पर ले जाता हूं, या मैं दूसरे फ़ंक्शन में भी मॉड्यूल को आयात करके अपने स्वयं के सामान्य नियम को तोड़ता हूं।
कोडपे

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

6

मैंने आत्म-परीक्षण कर रहे मॉड्यूल के लिए पहले इस नियम को तोड़ा है। यही है, वे आम तौर पर सिर्फ समर्थन के लिए उपयोग किए जाते हैं, लेकिन मैं उनके लिए एक मुख्य परिभाषित करता हूं ताकि यदि आप उन्हें स्वयं चलाते हैं तो आप उनकी कार्यक्षमता का परीक्षण कर सकते हैं। उस स्थिति में मैं कभी-कभी आयात करता हूं getoptऔर cmdसिर्फ मुख्य में, क्योंकि मैं चाहता हूं कि यह कोड पढ़ने वाले किसी व्यक्ति के लिए स्पष्ट हो कि इन मॉड्यूल का सामान्य ऑपरेशन से कोई लेना-देना नहीं है और केवल परीक्षण के लिए शामिल किया जा रहा है।


5

दो बार मॉड्यूल लोड करने के बारे में सवाल से आ रहा है - दोनों क्यों नहीं?

स्क्रिप्ट के शीर्ष पर एक आयात निर्भरता को इंगित करेगा और फ़ंक्शन में एक और आयात इस फ़ंक्शन को अधिक परमाणु बना देगा, जबकि प्रतीत होता है कि कोई प्रदर्शन नुकसान नहीं कर सकता है, क्योंकि लगातार आयात सस्ता है।


3

जब तक यह है importऔर नहीं from x import *, आपको उन्हें शीर्ष पर रखना चाहिए। यह वैश्विक नामस्थान में केवल एक नाम जोड़ता है, और आप PEP 8. प्लस से चिपक जाते हैं, यदि आपको बाद में कहीं और इसकी आवश्यकता होती है, तो आपको कुछ भी स्थानांतरित करने की आवश्यकता नहीं है।

यह कोई बड़ी बात नहीं है, लेकिन चूंकि लगभग कोई अंतर नहीं है जो मैं सुझाता हूं कि पीईपी 8 क्या कहता है।


3
दरअसल, from x import *एक फंक्शन के अंदर डालने से सिंटेक्सवर्निंग उत्पन्न होगी, कम से कम 2.5 में।
रिक कोपलैंड

3

Sqlalchemy में उपयोग किए जाने वाले वैकल्पिक दृष्टिकोण पर एक नज़र डालें: निर्भरता इंजेक्शन:

@util.dependencies("sqlalchemy.orm.query")
def merge_result(query, *args):
    #...
    query.Query(...)

ध्यान दें कि आयातित पुस्तकालय को एक डेकोरेटर में कैसे घोषित किया जाता है, और फ़ंक्शन के तर्क के रूप में पारित किया गया !

यह दृष्टिकोण कोड क्लीनर बनाता है, और एक बयान की तुलना में 4.5 गुना तेजी से काम करता है import!

बेंचमार्क: https://gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796


2

ऐसे मॉड्यूल में जो दोनों 'सामान्य' मॉड्यूल हैं और निष्पादित किए जा सकते हैं (जैसे कि ए if __name__ == '__main__': -section है), मैं आमतौर पर मॉड्यूल का आयात करता हूं जो केवल मुख्य अनुभाग के अंदर मॉड्यूल को निष्पादित करते समय उपयोग किया जाता है।

उदाहरण:

def really_useful_function(data):
    ...


def main():
    from pathlib import Path
    from argparse import ArgumentParser
    from dataloader import load_data_from_directory

    parser = ArgumentParser()
    parser.add_argument('directory')
    args = parser.parse_args()
    data = load_data_from_directory(Path(args.directory))
    print(really_useful_function(data)


if __name__ == '__main__':
    main()

1

एक और (शायद "कोने") का मामला है जहां यह importशायद ही कभी इस्तेमाल किए जाने वाले कार्यों के अंदर फायदेमंद हो सकता है : स्टार्टअप समय को छोटा करें।

मैंने एक छोटी सी IoT सर्वर पर चल रहे एक जटिल प्रोग्राम के साथ एक बार उस दीवार को हिट किया, जो कि एक सीरियल लाइन से कमांड को स्वीकार करता है और ऑपरेशन करता है, संभवतः बहुत ही जटिल ऑपरेशन।

importफ़ाइलों के शीर्ष पर बयान रखने का मतलब सर्वर शुरू होने से पहले सभी आयातों को संसाधित करना है; के बाद से importसूची शामिल jinja2, lxml, signxmlऔर अन्य "भारी वजन" (और SoC बहुत शक्तिशाली नहीं था) इसका मतलब मिनट पहले निर्देश से पहले वास्तव में मार डाला गया था।

OTOH उन कार्यों में सबसे अधिक आयात करता है जो मैं सेकंड में सीरियल लाइन पर सर्वर "जीवित" करने में सक्षम था। बेशक जब मॉड्यूल की वास्तव में आवश्यकता थी, तो मुझे इसकी कीमत चुकानी पड़ी (नोट: यह भी एक पृष्ठभूमि कार्य importको निष्क्रिय समय में करने के कारण कम किया जा सकता है )।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.