पायथन में रिश्तेदार आयात कैसे करें?


527

इस निर्देशिका संरचना की कल्पना करें:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

मैं कोडिंग कर रहा हूं mod1, और मुझे कुछ आयात करने की आवश्यकता है mod2। मैं इसे कैसे करूं?

मैंने कोशिश की from ..sub2 import mod2लेकिन मुझे "नॉन-पैकेज में एक सापेक्षित सापेक्षिक आयात" मिल रहा है।

मैं चारों ओर घूम गया लेकिन केवल " sys.pathहेरफेर" हैक पाया । क्या कोई साफ रास्ता नहीं है?


संपादित करें: मेरे सभी __init__.pyवर्तमान में खाली हैं

EDIT2: मैं यह करने के क्योंकि sub2 वर्गों है कि उप पैकेज (बांट लिया जाता शामिल कोशिश कर रहा हूँ sub1, subX, आदि)।

Edit3: मैं जिस व्यवहार की तलाश कर रहा हूं, वह पीईपी 366 में वर्णित है (धन्यवाद जॉन बी)


8
मैं आपको यह स्पष्ट करने के लिए आपके प्रश्न को अपडेट करने की सलाह देता हूं कि आप PEP 366 में संबोधित मुद्दे का वर्णन कर रहे हैं।
जॉन बी।

2
यह एक लंबी घुमावदार व्याख्या है, लेकिन यहां देखें: stackoverflow.com/a/10713254/1267156 मैंने एक बहुत ही समान प्रश्न का उत्तर दिया। कल रात तक मुझे यही समस्या थी।
सेवई 325

3
जो लोग एक मनमाना मार्ग पर स्थित मॉड्यूल को लोड करना चाहते हैं, उनके लिए यह देखें: stackoverflow.com/questions/67631/…
एवगेनी सर्गेव

2
संबंधित नोट पर, पायथन 3 आयात की डिफ़ॉल्ट हैंडलिंग को डिफ़ॉल्ट रूप से निरपेक्ष रूप से बदल देगा; सापेक्ष आयातों को स्पष्ट रूप से निर्दिष्ट करना होगा।
रोस

जवाबों:


337

हर कोई आपको यह बताना चाहता है कि सवाल का जवाब देने के बजाय आपको क्या करना चाहिए।

समस्या यह है कि आप mod1.py को दुभाषिए के तर्क के रूप में पास करके '__main__' के रूप में मॉड्यूल चला रहे हैं।

से पीईपी 328 :

पैकेज पदानुक्रम में उस मॉड्यूल की स्थिति निर्धारित करने के लिए सापेक्ष आयात एक मॉड्यूल की __name__ विशेषता का उपयोग करते हैं। यदि मॉड्यूल के नाम में कोई पैकेज जानकारी नहीं है (उदाहरण के लिए यह '__main__' पर सेट है) तो सापेक्ष आयात हल किए जाते हैं जैसे कि मॉड्यूल एक शीर्ष स्तर मॉड्यूल था, चाहे मॉड्यूल वास्तव में फ़ाइल सिस्टम पर स्थित हो।

पायथन 2.6 में, वे मुख्य मॉड्यूल के सापेक्ष संदर्भ मॉड्यूल की क्षमता जोड़ रहे हैं। पीईपी 366 परिवर्तन का वर्णन करता है।

अद्यतन : निक कॉघलान के अनुसार, अनुशंसित विकल्प -m स्विच का उपयोग करके पैकेज के अंदर मॉड्यूल को चलाने के लिए है।


2
यहाँ उत्तर में आपके प्रोग्राम के हर एंट्री पॉइंट पर sys.path के साथ गड़बड़ करना शामिल है। मुझे लगता है कि ऐसा करने का एकमात्र तरीका है।
निक रिटलैक

76
अनुशंसित विकल्प -mस्विच का उपयोग करके पैकेज के अंदर मॉड्यूल चलाने के बजाय, सीधे उनके फ़ाइलनाम को निर्दिष्ट करके है।
ncoghlan

127
मुझे समझ में नहीं आता: यहाँ जवाब कहाँ है? ऐसी निर्देशिका संरचना में कोई मॉड्यूल कैसे आयात कर सकता है?
टॉम

27
@Tom: इस उदाहरण में, mod1 होगा from sub2 import mod2। फिर, mod1 को चलाने के लिए, ऐप के भीतर से, करें python -m sub1.mod1
जिओनीज चामिओसोव

11
@XiongChiamiov: इसका मतलब यह नहीं है कि आप ऐसा नहीं कर सकते हैं यदि आपका अजगर एक आवेदन में एम्बेडेड है, तो आपके पास अजगर कमांड लाइन स्विच तक पहुंच नहीं है?
लार्स

130

यहाँ समाधान है जो मेरे लिए काम करता है:

मैं from ..sub2 import mod2 और फिर रिश्तेदार आयात करता हूं, अगर मैं चलाना चाहता हूं mod1.pyतो मैं appपायथन-एम स्विच का उपयोग करके मॉड्यूल की मूल निर्देशिका में जाता हूं और मॉड्यूल को चलाता हूं python -m app.sub1.mod1

रिश्तेदार आयात के साथ यह समस्या क्यों होती है, इसका वास्तविक कारण यह है कि सापेक्ष आयात __name__मॉड्यूल की संपत्ति को ले कर काम करता है । यदि मॉड्यूल को सीधे चलाया जा रहा है, तो __name__इसे सेट किया गया है __main__और इसमें पैकेज संरचना के बारे में कोई जानकारी नहीं है। और, यही कारण है कि अजगर relative import in non-packageत्रुटि के बारे में शिकायत करता है।

तो, -m स्विच का उपयोग करके आप अजगर को पैकेज संरचना की जानकारी प्रदान करते हैं, जिसके माध्यम से यह सापेक्ष आयात को सफलतापूर्वक हल कर सकता है।

रिश्तेदार आयात करते समय मुझे कई बार इस समस्या का सामना करना पड़ा है। और, पिछले सभी उत्तरों को पढ़ने के बाद, मैं अभी भी यह पता लगाने में सक्षम नहीं था कि सभी फाइलों में बॉयलरप्लेट कोड डालने की आवश्यकता के बिना, इसे कैसे साफ तरीके से हल किया जाए। (हालांकि कुछ टिप्पणियाँ वास्तव में मददगार थीं, @ncoghlan और @XiongChiamiov के लिए धन्यवाद)

आशा है कि यह किसी ऐसे व्यक्ति की मदद करता है जो रिश्तेदार आयात समस्या से लड़ रहा है, क्योंकि पीईपी के माध्यम से जाना वास्तव में मजेदार नहीं है।


9
सर्वश्रेष्ठ उत्तर IMHO: न केवल यह बताता है कि ओपी के पास मुद्दा क्यों था, बल्कि अपने मॉड्यूल के आयात के तरीके को बदलने के बिना इसे हल करने का एक तरीका भी ढूंढता है । बाद में, ओपी के सापेक्ष आयात ठीक थे। अपराधी बाहरी पैकेजों तक पहुंच की कमी था जब सीधे स्क्रिप्ट के रूप में चल रहा -mथा , कुछ हल करने के लिए डिज़ाइन किया गया था।
MestreLion

26
यह भी ध्यान दें: यह उत्तर प्रश्न के 5 साल बाद था। ये सुविधाएँ उस समय उपलब्ध नहीं थीं।
जेरेमीकुन

1
यदि आप उसी निर्देशिका से एक मॉड्यूल आयात करना चाहते हैं जो आप कर सकते हैं from . import some_module
रोटारटी

124
main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. तुम दौड़ो python main.py
  2. main.py कर देता है: import app.package_a.module_a
  3. module_a.py कर देता है import app.package_b.module_b

वैकल्पिक रूप से 2 या 3 उपयोग कर सकते हैं: from app.package_a import module_a

जब तक आप appअपने PYTHONPATH में काम करेंगे । main.pyतब कहीं भी हो सकता है।

तो आप setup.pyपूरे ऐप पैकेज को कॉपी (इंस्टॉल) करें और टारगेट सिस्टम के पाइथन फोल्डर को सब-पैकेज और main.pyसिस्टम के स्क्रिप्ट फोल्डर को टारगेट करने के लिए लिखें ।


3
बहुत बढ़िया जवाब। क्या PYTHONPATH में पैकेज स्थापित किए बिना उस तरह से आयात करने का कोई तरीका है?
औराहम जूल

4
अतिरिक्त पढ़ने का सुझाव दें: blog.habnab.it/blog/2013/07/21/python-packages-and-you
nosklo

6
फिर, एक दिन, ऐप का नाम बदलकर test_app करने की आवश्यकता है। क्या हुआ होगा? आपको सभी स्रोत कोड बदलने होंगे, आयात करें app.package_b.module_b -> test_app.package_b.module_b। यह पूरी तरह से बुरा अभ्यास है ... और हमें पैकेज के भीतर रिश्तेदार आयात का उपयोग करने की कोशिश करनी चाहिए।
11

49

"एक प्रतिमान के रूप में पैकेज के भीतर स्क्रिप्ट चलाने वाले गुइडो विचार" (अस्वीकृत PEP-3122 )

मैंने बहुत समय बिताया है कि एक समाधान खोजने की कोशिश कर रहा हूं, स्टैक ओवरफ्लो पर यहां संबंधित पोस्ट पढ़ रहा हूं और खुद से कह रहा हूं "एक बेहतर तरीका होना चाहिए!"। लगता है, वहाँ नहीं है।


10
नोट: पहले से ही उल्लेख किए गए pep-366 ( pep-3122 के समान समय के आसपास बनाया गया ) समान क्षमताएं प्रदान करता है, लेकिन एक अलग पिछड़े-संगत कार्यान्वयन का उपयोग करता है अर्थात, यदि आप स्क्रिप्ट के रूप में पैकेज के अंदर मॉड्यूल चलाना चाहते हैं और स्पष्ट सापेक्ष आयात का उपयोग करते हैं इसमें तब आप इसे -mस्विच का उपयोग करके चला सकते हैं : python -m app.sub1.mod1या app.sub1.mod1.main()एक शीर्ष-स्तरीय स्क्रिप्ट (उदाहरण के लिए, सेट-थ्रू सेटअप में परिभाषित एंट्री_प्वाइंट्स से उत्पन्न)।
jfs

सेटपूल और एंट्री पॉइंट का उपयोग करने के लिए +1 - यह स्क्रिप्ट को सेट करने का एक उचित तरीका है, जिसे बाहर से चलाया जाएगा, एक अच्छी तरह से परिभाषित स्थान पर, जैसा कि PYTHONPATH को हैक करने के विरोध में है
रीसेंसीफैक्ट

38

यह 100% हल है:

  • एप्लिकेशन /
    • main.py
  • समायोजन/
    • local_setings.py

एप्लिकेशन / main.py में आयात सेटिंग / local_setting.py:

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')

2
धन्यवाद! सभी ppl मुझे स्क्रिप्ट के भीतर इसे हल करने के तरीके बताने के बजाय अपनी स्क्रिप्ट चलाने के लिए मजबूर कर रहे थे। लेकिन मुझे इस्तेमाल करने के लिए कोड बदलना पड़ा sys.path.insert(0, "../settings")और फिरfrom local_settings import *
Vit Bernatik

25
def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

मैं पथ से मॉड्यूल आयात करने के लिए इस स्निपेट का उपयोग कर रहा हूं, आशा है कि मदद करता है


2
मैं इस स्निपेट का उपयोग कर रहा हूं, इंपैक्ट मॉड्यूल (जैसा कि यहां बताया गया है [1]) के साथ बहुत प्रभाव डालता है। [१]: stackoverflow.com/questions/1096216/…
Xiong Chiamiov

7
संभवतः, sys.path.append (पथ) को sys.path.insert (0, पथ) से बदला जाना चाहिए, और sys.path [-1] को sys.path [0] से बदल दिया जाना चाहिए। अन्यथा फ़ंक्शन गलत मॉड्यूल को आयात करेगा, अगर खोज पथ में समान नाम वाला कोई मॉड्यूल पहले से ही है। जैसे, यदि वर्तमान dir में "some.py" है, तो import_path ("/ import / some.py") गलत फ़ाइल आयात करेगा।
एलेक्स चे

मैं सहमत हूँ! कभी-कभी अन्य रिश्तेदार आयात मिसाल बनेंगे। Sys.path.insert
iElectric

आप x आयात y (या *) के व्यवहार को कैसे दोहराएंगे?
लेव्सकेव

यह स्पष्ट नहीं है, कृपया ओपी समस्या को हल करने के लिए इस स्क्रिप्ट का पूर्ण उपयोग निर्दिष्ट करें।
मर्गलूम

21

nosklo'sउदाहरणों के साथ उत्तर की व्याख्या

नोट: सभी __init__.pyफाइलें खाली हैं।

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

एप्लिकेशन / package_a / fun_a.py

def print_a():
    print 'This is a function in dir package_a'

एप्लिकेशन / package_b / fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

यदि आप $ python main.pyइसे चलाते हैं तो रिटर्न:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • मेनडोमो करता है: from app.package_b import fun_b
  • fun_b.py करता है from app.package_a.fun_a import print_a

इसलिए फ़ोल्डर में फ़ाइल का package_bउपयोग फ़ोल्डर में फ़ाइल package_a, जो आप चाहते हैं। सही??


12

यह दुर्भाग्य से sys.path हैक है, लेकिन यह काफी अच्छी तरह से काम करता है।

मुझे एक और परत के साथ इस समस्या का सामना करना पड़ा: मेरे पास पहले से ही निर्दिष्ट नाम का एक मॉड्यूल था, लेकिन यह गलत मॉड्यूल था।

मैं जो करना चाहता था वह निम्नलिखित था (जिस मॉड्यूल से मैं काम कर रहा था वह मॉड्यूल 3 था):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

ध्यान दें कि मैंने पहले से ही mymodule स्थापित किया है, लेकिन मेरी स्थापना में मेरे पास "mymodule1" नहीं है

और मुझे एक ImportError मिलेगी क्योंकि यह मेरे स्थापित मॉड्यूल से आयात करने की कोशिश कर रहा था।

मैंने sys.path.append करने की कोशिश की, और यह काम नहीं किया। क्या काम किया था एक sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

एक हैक की तरह है, लेकिन यह सब काम करने के लिए मिल गया! तो ध्यान रखें, यदि आप चाहते हैं कि आपका निर्णय अन्य रास्तों को ओवरराइड करने के लिए है तो आपको इसे काम करने के लिए sys.path.insert (0, pathname) का उपयोग करने की आवश्यकता है! यह मेरे लिए एक बहुत निराशा की बात है, लोगों का कहना है कि "append" फ़ंक्शन का उपयोग करने के लिए sys.path को आवंटित करें, लेकिन यह काम नहीं करता है यदि आपके पास पहले से ही एक मॉड्यूल परिभाषित है (मुझे यह बहुत अजीब व्यवहार लगता है)


sys.path.append('../')मेरे लिए ठीक काम करता है (पायथन 3.5.2)
Nister

मुझे लगता है कि यह ठीक है क्योंकि यह हैक को निष्पादन योग्य बनाता है और अन्य मॉड्यूल को प्रभावित नहीं करता है जो आपके पैकेज पर निर्भर हो सकते हैं।
टॉम रसेल

10

मुझे केवल अपने संदर्भ के लिए यहां डाल दें। मुझे पता है कि यह अच्छा पायथन कोड नहीं है, लेकिन मुझे उस प्रोजेक्ट के लिए स्क्रिप्ट की जरूरत है, जिस पर मैं काम कर रहा था और मैं स्क्रिप्ट को एक scriptsनिर्देशिका में रखना चाहता था ।

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

9

जैसा कि @EvgeniSergeev ओपी की टिप्पणियों में कहता है, आप एक .pyफ़ाइल से कोड को किसी मनमाने स्थान पर आयात कर सकते हैं :

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

यह इस SO उत्तर से लिया गया है ।



2

से अजगर डॉक ,

पायथन 2.5 में, आप एक from __future__ import absolute_importनिर्देश का उपयोग करके आयात के व्यवहार को पूर्ण आयात पर स्विच कर सकते हैं । यह पूर्ण-आयात व्यवहार भविष्य के संस्करण (शायद पायथन 2.7) में डिफ़ॉल्ट हो जाएगा। एक बार पूर्ण आयात डिफ़ॉल्ट हो जाने के बाद, import stringहमेशा मानक लाइब्रेरी का संस्करण मिलेगा। यह सुझाव दिया जाता है कि उपयोगकर्ताओं को यथासंभव पूर्ण आयात का उपयोग करना शुरू करना चाहिए, इसलिए from pkg import stringआपके कोड में लिखना शुरू करना बेहतर होगा


1

मैंने पाया कि शीर्ष फ़ोल्डर में "PYTHONPATH" पर्यावरण चर सेट करना अधिक आसान है:

bash$ export PYTHONPATH=/PATH/TO/APP

फिर:

import sub1.func1
#...more import

बेशक, PYTHONPATH "वैश्विक" है, लेकिन इसने मेरे लिए अभी तक परेशानी नहीं बढ़ाई है।


यह अनिवार्य रूप से है कि कैसे virtualenvआप अपने आयात विवरण को प्रबंधित कर सकते हैं।
byxor

1

जॉन बी ने जो कहा उसके शीर्ष पर, ऐसा लगता है कि __package__परिवर्तन को स्थापित करने के बजाय चर को मदद करनी चाहिए, __main__जो अन्य चीजों को पेंच कर सकता है। लेकिन जहां तक ​​मैं परीक्षण कर सका, यह पूरी तरह से काम नहीं करना चाहिए जैसा कि इसे करना चाहिए।

मेरे पास एक ही समस्या है और न ही पीईपी 328 या 366 समस्या को पूरी तरह से हल करते हैं, क्योंकि दिन के अंत तक दोनों को पैकेज के प्रमुख की आवश्यकता होती है sys.path, जहां तक ​​मैं समझ सकता हूं।

मुझे यह भी उल्लेख करना चाहिए कि मैंने यह नहीं पाया कि स्ट्रिंग को कैसे प्रारूपित किया जाए जो उन चर में जाना चाहिए। है "package_head.subfolder.module_name"या क्या?


0

आपको मॉड्यूल के रास्ते को जोड़ना होगा PYTHONPATH:

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

1
यह मोटे तौर पर जोड़-तोड़ के समान है sys.path, क्योंकि इससे sys.pathशुरू होता हैPYTHONPATH
जोरिल

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