पायथन 3 का उपयोग कर ज्यूपिटर नोटबुक में सापेक्ष आयात के साथ एक अन्य निर्देशिका में रखे गए मॉड्यूल से स्थानीय फ़ंक्शन आयात करें


127

मेरे पास निम्नलिखित के समान एक निर्देशिका संरचना है

meta_project
    project1
        __init__.py
        lib
            module.py
            __init__.py
    notebook_folder
        notebook.jpynb

जब में काम कर रहा notebook.jpynbहै, तो मैं एक समारोह का उपयोग करने के एक रिश्तेदार आयात इस्तेमाल करने की कोशिश function()में module.pyसाथ:

from ..project1.lib.module import function

मुझे निम्नलिखित त्रुटि मिलती है:

SystemError                               Traceback (most recent call last)
<ipython-input-7-6393744d93ab> in <module>()
----> 1 from ..project1.lib.module import function

SystemError: Parent module '' not loaded, cannot perform relative import

क्या रिश्तेदार आयात का उपयोग करके इसे प्राप्त करने का कोई तरीका है?

ध्यान दें, नोटबुक सर्वर को meta_projectडायरेक्ट्री के स्तर पर त्वरित किया जाता है , इसलिए इसमें उन फ़ाइलों की जानकारी तक पहुंच होनी चाहिए।

ध्यान दें, यह भी कि कम से कम मूल रूप से इरादा project1के रूप में एक मॉड्यूल के रूप में नहीं सोचा गया था और इसलिए एक __init__.pyफ़ाइल नहीं है , यह सिर्फ एक फ़ाइल-सिस्टम निर्देशिका के रूप में था। यदि समस्या के समाधान के लिए इसे एक मॉड्यूल के रूप में और एक __init__.pyफ़ाइल (यहां तक ​​कि एक रिक्त) सहित उपचार की आवश्यकता होती है जो ठीक है, लेकिन ऐसा करना समस्या को हल करने के लिए पर्याप्त नहीं है।

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


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


1
क्या __init__आपके पैकेज निर्देशिका में कोई फाइल है?
लोहे की मुट्ठी

हां, libडायरेक्टरी में।
mpacer

कृपया, अपने प्रश्न में अपनी निर्देशिका संरचना में इसका उल्लेख करें
आयरन फिस्ट

जैसे ही मैंने आपकी पहली टिप्पणी देखी, वैसे ही संपादित किया :)। इसे पकड़ने के लिए धन्यवाद।
mpacer

जवाबों:


174

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

मेरा समाधान यह था कि नोटबुक में इस तरह एक स्निपेट जोड़कर उस अतिरिक्त मॉड्यूल आयात पथ के पायथन को बताया जाए:

import os
import sys
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
    sys.path.append(module_path)

यह आपको मॉड्यूल पदानुक्रम से वांछित फ़ंक्शन आयात करने की अनुमति देता है:

from project1.lib.module import function
# use the function normally
function(...)

ध्यान दें कि यदि आपके पास पहले से ही नहीं है, तो प्रोजेक्ट 1 / और lib / फ़ोल्डरों में खाली __init__.pyफ़ाइलों को जोड़ना आवश्यक है ।


6
यह एक सापेक्ष स्थान के कम या ज्यादा का उपयोग करके एक पैकेज को आयात करने में सक्षम होने की समस्या को हल करता है, लेकिन केवल अप्रत्यक्ष रूप से। मुझे पता है कि मैथियस बूसोनियर (@ एमआट ऑन एसई) और युवी पांडा (@ एसयूवी ऑन एसई) github.com/ipython/ipynb विकसित कर रहे हैं जो इसे और अधिक सीधे संबोधित करेंगे (जैसे, मानक सिंटैक्स का उपयोग करके रिश्तेदार को एक बार उनके पैकेज की अनुमति देकर) आयातित है)। मैं आपके उत्तर को अभी के लिए स्वीकार करूंगा, और जब उनका समाधान दूसरों के उपयोग के लिए पूरी तरह से तैयार हो जाएगा, तो मैं शायद इसका उपयोग करने के तरीके पर उत्तर लिखूंगा, या उनमें से किसी एक को ऐसा करने के लिए कहूंगा।
1

खाली init को इंगित करने के लिए धन्यवाद।। मैं एक अजगर नौसिखिया हूँ और आयात करने के लिए मेरी कक्षाएं लेने में परेशानी हो रही थी। मैं मॉड्यूल टिप्पणी त्रुटि पाई हो रही थी, खाली जोड़ने init .py समस्या तय!
पैट ग्रैडी

5
खाली init .py फ़ाइल की अब अजगर 3 में जरूरत नहीं है।
CathyQian

FYI करें: नोटबुक के लिए एक दर्शक है: nbviewer.jupyter.org/github/qPRC/qPRC/blob/master/notebook/…
थोरोक

26

नोटबुक में काम करते समय सबमॉडल्स को अमूर्त कोड में सर्वोत्तम प्रथाओं की खोज करने के लिए यहां आया था। मुझे यकीन नहीं है कि सबसे अच्छा अभ्यास है। मैं यह प्रस्ताव कर रहा हूं।

एक परियोजना पदानुक्रम जैसे:

├── ipynb
   ├── 20170609-Examine_Database_Requirements.ipynb
   └── 20170609-Initial_Database_Connection.ipynb
└── lib
    ├── __init__.py
    └── postgres.py

और से 20170609-Initial_Database_Connection.ipynb:

    In [1]: cd ..

    In [2]: from lib.postgres import database_connection

यह काम करता है क्योंकि डिफ़ॉल्ट रूप से जुपिटर नोटबुक cdकमांड को पार्स कर सकता है । ध्यान दें कि यह पायथन नोटबुक मैजिक का उपयोग नहीं करता है। यह बस बिना किसी तैयारी के काम करता है%bash

ध्यान में रखते हुए एक 100 मैं डोकर में काम कर रहा हूँ में से एक का उपयोग कर से बाहर है कि 99 बार परियोजना Jupyter डोकर छवियों , निम्नलिखित संशोधन है idempotent

    In [1]: cd /home/jovyan

    In [2]: from lib.postgres import database_connection

धन्यवाद। वास्तव में इस रिश्तेदार आयात के प्रतिबंध भयानक हैं।
माइकल

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

अफसोस की बात है, सबसे ज्यादा हैक की गई चीज मैं अजगर में करता हूं। फिर भी, मैं एक बेहतर समाधान नहीं ढूँढ सकता।
द ग्रीमस्मिंटिस्ट

साधारण सुस्ती के लिए (एक ही सेल को कई बार चलाने और एक ही परिणाम प्राप्त करने की अनुमति) if os.path.isdir('../lib/'): os.chdir('../lib'):; या, बेहतर है, ../lib/db/अपने साथ का उपयोग करें postgres.pyताकि गलती से एक उच्च निर्देशिका तक chdir भी नहीं जिसमें एक और भी हो lib
माइकल

1
मुझे यह समाधान पसंद है जब तक कि मैं गलती से cd ..दो बार निष्पादित नहीं हुआ ।
मिन्हले_र

15

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

इस प्रकार, निम्नलिखित परियोजना संरचना होने:

project
|__notebooks
   |__explore
      |__ notebook1.ipynb
      |__ notebook2.ipynb
      |__ project_path.py
   |__ explain
       |__notebook1.ipynb
       |__project_path.py
|__lib
   |__ __init__.py
   |__ module.py

मैंने फाइल जोड़ दी project_path.py प्रत्येक नोटबुक उपनिर्देशिका ( notebooks/exploreऔर notebooks/explain) में को । इस फ़ाइल में रिश्तेदार आयात के लिए कोड है (@metakermit से):

import sys
import os

module_path = os.path.abspath(os.path.join(os.pardir, os.pardir))
if module_path not in sys.path:
    sys.path.append(module_path)

इस तरह, मुझे project_path.pyफ़ाइल के भीतर सापेक्ष आयात करने की आवश्यकता है , न कि नोटबुक में। फिर नोटबुक फ़ाइलों को आयात करने की आवश्यकता होगीproject_path से पहले आयातlib । उदाहरण के लिए 0.0-notebook.ipynb:

import project_path
import lib

यहां पर चेतावनी यह है कि आयात को उलटने से काम नहीं चलेगा। यह काम नहीं करता:

import lib
import project_path

इस प्रकार आयात के दौरान देखभाल की जानी चाहिए।


3

मैं सिर्फ इस सुंदर समाधान मिल गया है:

import sys; sys.path.insert(0, '..') # add parent folder path where lib folder is
import lib.store_load # store_load is a file on my library folder

आप बस उस फ़ाइल के कुछ कार्य चाहते हैं

from lib.store_load import your_function_name

यदि अजगर संस्करण> = 3.3 आपको फ़ोल्डर में init.py फ़ाइल की आवश्यकता नहीं है


3
मुझे यह बहुत मददगार लगा। मैं जोड़ूंगा कि निम्नलिखित संशोधन को जोड़ा जाना चाहिए ->if ".." not in sys.path: ... sys.path.insert(0,"..")
याकोव ब्रेसलर

2

इस विषय पर स्वयं शोध करना और मेरे द्वारा सुझाए गए उत्तरों को पढ़ने के लिए पथप्रदर्शक पुस्तकालय का उपयोग करना चाहिए के बाद से यह वर्तमान कार्यशील निर्देशिका को बदलने के लिए एक संदर्भ प्रबंधक प्रदान करता है।

आपके पास फिर कुछ ऐसा है

import path
if path.Path('../lib').isdir():
    with path.Path('..'):
        import lib

हालाँकि, आप केवल isdirकथन को छोड़ सकते हैं ।

यहां मैं प्रिंट स्टेटमेंट जोड़ूंगा कि जो हो रहा है उसे फॉलो करना आसान है

import path
import pandas

print(path.Path.getcwd())
print(path.Path('../lib').isdir())
if path.Path('../lib').isdir():
    with path.Path('..'):
        print(path.Path.getcwd())
        import lib
        print('Success!')
print(path.Path.getcwd())

इस उदाहरण में कौन सा आउटपुट (जहां लिबर है /home/jovyan/shared/notebooks/by-team/data-vis/demos/lib):

/home/jovyan/shared/notebooks/by-team/data-vis/demos/custom-chart
/home/jovyan/shared/notebooks/by-team/data-vis/demos
/home/jovyan/shared/notebooks/by-team/data-vis/demos/custom-chart

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


यह% ऑटोरेलोड के साथ संयोजन में काम नहीं करेगा, क्योंकि मॉड्यूल पथ पुनः लोड समय पर नहीं मिलेगा
जोहान्स

1

यहाँ मेरे 2 सेंट हैं:

आयात sys

उस पथ को मैप करें जहां मॉड्यूल फ़ाइल स्थित है। मेरे मामले में यह डेस्कटॉप था

sys.path.append ( '/ उपयोगकर्ताओं / जॉन / डेस्कटॉप')

या तो पूरे मैपिंग मॉड्यूल को आयात करें लेकिन आपको मैपिंग जैसी कक्षाओं को मैप करने के लिए .notation का उपयोग करना होगा। शिपिंग ()

आयात मानचित्रण # mapping.py मेरी मॉड्यूल फ़ाइल का नाम है

shipit = mapping.Shipment () #Shipment उस वर्ग का नाम है जिसका उपयोग मुझे मैपिंग मॉड्यूल में करने की आवश्यकता है

या मैपिंग मॉड्यूल से विशिष्ट वर्ग का आयात करें

मैपिंग से आयात मैपिंग

shipit = शिपमेंट () # अब आपको .notation का उपयोग करने की आवश्यकता नहीं है


0

मैंने पाया है कि अजगर-डॉटेनव इस मुद्दे को बहुत प्रभावी ढंग से हल करने में मदद करता है। आपकी परियोजना संरचना थोड़ा बदलकर समाप्त हो जाती है, लेकिन आपकी नोटबुक में कोड थोड़ा सरल और पूरे नोटबुक में सुसंगत है।

अपने प्रोजेक्ट के लिए, थोड़ा इंस्टाल करें।

pipenv install python-dotenv

फिर, परियोजना में परिवर्तन:

├── .env (this can be empty)
├── ipynb
   ├── 20170609-Examine_Database_Requirements.ipynb
   └── 20170609-Initial_Database_Connection.ipynb
└── lib
    ├── __init__.py
    └── postgres.py

और अंत में, आपका आयात इसमें परिवर्तन करता है:

import os
import sys

from dotenv import find_dotenv


sys.path.append(os.path.dirname(find_dotenv()))

इस पैकेज के लिए एक +1 यह है कि आपकी नोटबुक कई निर्देशिकाओं को गहरा कर सकती है। पाइथन-डॉटेनव पैरेंट डायरेक्टरी में सबसे नज़दीक मिलेगा और इसका उपयोग करेगा। इस दृष्टिकोण के लिए A2 यह है कि जुपाइटर स्टार्टअप पर .env फ़ाइल से पर्यावरण चर को लोड करेगा। दोहरा झटका।

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