Python 3 kullanarak Jupyter Notebook'ta göreceli içe aktarmalarla başka bir dizinde bulunan bir modülden yerel işlevi içe aktarın


127

Aşağıdakine benzer bir dizin yapım var

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

Çalışırken notebook.jpynbbir işleve erişmek için göreli ithalat kullanmaya çalışırsanız function()içindemodule.py birlikte:

from ..project1.lib.module import function

Şu hatayı alıyorum:

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

Bunu göreli ithalatı kullanarak çalıştırmanın bir yolu var mı?

Not, dizüstü bilgisayar sunucusu şu düzeydedir: meta_project dizin , dolayısıyla bu dosyalardaki bilgilere erişimi olması gerektiğini unutmayın.

Ayrıca, en azından başlangıçta amaçlandığı project1gibi bir modül olarak düşünülmediğine ve bu nedenle bir __init__.pydosyaya sahip olmadığına, sadece bir dosya sistemi dizini olarak kastedildiğine dikkat edin. Sorunun çözümü, onu bir modül olarak ele almayı ve bir __init__.pydosya (hatta boş bir dosya) eklemeyi gerektiriyorsa, bu sorun değildir, ancak bunu yapmak sorunu çözmek için yeterli değildir.

Bu dizini makineler arasında paylaşıyorum ve ilgili içe aktarmalar her yerde aynı kodu kullanmama izin veriyor ve hızlı prototip oluşturma için sık sık not defterleri kullanıyorum, bu nedenle mutlak yolları birlikte hacklemeyi içeren önerilerin yardımcı olma olasılığı düşüktür.


Düzenleme: Bu, genel olarak Python 3'teki göreli içe aktarmalardan bahseden ve - özellikle - bir paket dizininden bir komut dosyası çalıştıran Python 3'teki Göreli içe aktarmalardan farklıdır . Bu, hem farklı genel hem de özel yönleri olan başka bir dizindeki yerel bir modüldeki bir işlevi çağırmaya çalışan bir jupyter not defterinde çalışmakla ilgilidir.


1
__init__paket dizininizde herhangi bir dosya var mı?
Demir Yumruk

Evet, libdizinde.
mpacer

Lütfen, sorunuzdaki dizin yapınızda bundan bahsedin
Iron Fist

İlk yorumunuzu görür görmez bu düzenlemeyi yaptım :). Bunu yakaladığın için teşekkürler.
mpacer

Yanıtlar:


174

Bu defterde neredeyse seninle aynı örneğe sahiptim burada bitişik bir modülün işlevini KURU bir şekilde kullanmak istedim.

Çözümüm, not defterine bunun gibi bir pasaj ekleyerek Python'a bu ek modül içe aktarma yolunu söylemekti:

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

Bu, istenen işlevi modül hiyerarşisinden içe aktarmanıza olanak tanır:

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

Henüz sahip değilseniz __init__.py, project1 / ve lib / klasörlerine boş dosyalar eklemeniz gerektiğini unutmayın .


6
Bu, bir paketi aşağı yukarı göreceli bir konum kullanarak, ancak yalnızca dolaylı olarak içe aktarabilme sorununu çözer. Matthias Bussonier (@matt SE'de) ve Yuvi Panda'nın (SE'de @yuvi) bunu daha doğrudan ele alacak olan github.com/ipython/ipynb geliştirdiklerini biliyorum (ör. içe aktarılır). Cevabınızı şimdilik kabul edeceğim ve çözümleri başkalarının kullanması için tamamen hazır olduğunda, muhtemelen ya nasıl kullanılacağına dair bir cevap yazacağım ya da onlardan birinin bunu yapmasını isteyeceğim.
mpacer

Boş işaret için teşekkürler init Ben piton acemi olduğum .py ve sorun ithalat benim sınıfları alma başlamıştı. Modül notu hataları bulundu, boş init ekleyerek sorunu çözdüm!
Pat Grady

5
Python 3'te boş init .py dosyasına artık gerek yok.
CathyQian

Bilginize: not defteri için bir görüntüleyici var: nbviewer.jupyter.org/github/qPRC/qPRC/blob/master/notebook/…
thoroc

26

Defterlerde çalışırken kodu alt modüllere soyutlamak için en iyi uygulamaları aramak için buraya geldim. Bir en iyi uygulama olduğundan emin değilim. Ben bunu öneriyorum.

Böyle bir proje hiyerarşisi:

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

Ve şuradan 20170609-Initial_Database_Connection.ipynb:

    In [1]: cd ..

    In [2]: from lib.postgres import database_connection

Bu çalışır çünkü varsayılan olarak Jupyter Notebook cdkomutu ayrıştırabilir . Bunun Python Notebook büyüsünü kullanmadığını unutmayın. Ön harcamadan basitçe çalışır %bash.

Ben birini kullanarak Docker çalışıyorum bir 100 üzerinden o 99 kez düşünüldüğünde Proje Jupyter Docker görüntüleri , aşağıdaki modifikasyon olan İdempotent

    In [1]: cd /home/jovyan

    In [2]: from lib.postgres import database_connection

Teşekkürler. Bu göreli ithalatın kısıtlamaları gerçekten korkunç.
Michael

Ben de chdiryola eklemek yerine kullanıyorum , çünkü hem ana depodan içe aktarmak hem de oradaki bazı dosyalarla arayüz oluşturmakla ilgileniyorum.
TheGrimmScientist

Ne yazık ki, python'da yaptığım en çok hacklenen şey. Yine de daha iyi bir çözüm bulamıyorum.
TheGrimmScientist

basit idempotence için (aynı hücrenin birden çok kez çalışmasına ve aynı sonucu almasına izin vermek) if os.path.isdir('../lib/'): os.chdir('../lib'):; veya, daha iyi, kullanımı ../lib/db/ile sizin postgres.pyböylece yanlışlıkla yüksek bir dizin de başka içeren kadar chdir değil lib.
michael

1
Yanlışlıkla cd ..iki kez infaz edene kadar bu çözümü seviyorum .
minhle_r7

15

Şimdiye kadar, kabul edilen cevap benim için en iyisi oldu. Bununla birlikte, benim endişem her zaman notebooksdizini alt dizinlere yeniden düzenleyebileceğim vemodule_path ve her not defterinde olmuştur. Gerekli modülleri içe aktarmak için her bir not defteri dizinine bir python dosyası eklemeye karar verdim.

Böylece aşağıdaki proje yapısına sahip olmak:

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

Dosyayı project_path.pyher not defteri alt dizinine ( notebooks/exploreve notebooks/explain) ekledim . Bu dosya, göreceli içe aktarım kodunu içerir (@metakermit'ten):

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)

Bu şekilde, project_path.pynot defterlerinde değil dosya içinde göreli içe aktarmalar yapmam gerekiyor . Bu durumda not defteri dosyalarının içe aktarılmadan project_pathönce içe aktarılması gerekir lib. Örneğin 0.0-notebook.ipynb:

import project_path
import lib

Buradaki uyarı, ithalatı tersine çevirmenin işe yaramayacağıdır. BU ÇALIŞMIYOR:

import lib
import project_path

Bu nedenle ithalat sırasında dikkatli olunmalıdır.


3

Bu güzel çözümü yeni buldum:

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

Sadece o dosyanın bazı işlevlerini istiyorsun

from lib.store_load import your_function_name

Python sürümü> = 3.3 ise, klasörde init.py dosyasına ihtiyacınız yoktur.


3
Bunu çok yararlı buldum. Aşağıdaki değişikliğin eklenmesi gerektiğini ekleyeceğim ->if ".." not in sys.path: ... sys.path.insert(0,"..")
Yaakov Bressler

2

Bu konuyu kendim araştırmak ve cevapları okuduktan sonra , mevcut çalışma dizinini değiştirmek için bir bağlam yöneticisi sağladığı için path.py kitaplığını kullanmanızı tavsiye ederim .

Sonra bir şeye sahipsin

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

Yine de, isdirifadeyi atlayabilirsiniz .

Neler olduğunu takip etmeyi kolaylaştırmak için buraya basılı ifadeler ekleyeceğim

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())

bu örnekte hangi çıktılar (lib'nin olduğu yerde /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

Çözüm bir bağlam yöneticisi kullandığından, çekirdeğiniz hücreden önce hangi durumda olursa olsun ve kütüphane kodunuzu içe aktararak hangi istisnalar atılmış olursa olsun, önceki çalışma dizininize geri dönmeniz garanti edilir.


Modül yolu yeniden yükleme zamanında bulunmayacağından, bu% autoreload ile birlikte çalışmaz
Johannes

1

İşte benim 2 sentim:

ithalat sys

modül dosyasının bulunduğu yolu eşleyin. Benim durumumda masaüstüydü

sys.path.append ( '/ Kullanıcılar / John / Masaüstü')

Ya tüm eşleme modülünü içe aktarın ANCAK daha sonra mapping gibi sınıfları eşlemek için. Notasyonunu kullanmanız gerekir.

içe aktarma eşlemesi # mapping.py modül dosyamın adıdır

shipit = mapping.Shipment () #Shipment, haritalama modülünde kullanmam gereken sınıfın adıdır

Veya eşleme modülünden belirli sınıfı içe aktarın

haritalamadan içe aktarma Eşleme

shipit = Gönderi () # Artık. notasyonunu kullanmak zorunda değilsiniz


0

Python-dotenv'nin bu sorunu oldukça etkili bir şekilde çözmeye yardımcı olduğunu buldum . Proje yapınız biraz değişiyor, ancak dizüstü bilgisayarınızdaki kod dizüstü bilgisayarlarda biraz daha basit ve tutarlı.

Projeniz için biraz kurulum yapın.

pipenv install python-dotenv

Ardından proje şu şekilde değişir:

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

Ve son olarak, içe aktarmanız şu şekilde değişir:

import os
import sys

from dotenv import find_dotenv


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

Bu paket için +1, not defterlerinizin birkaç dizin derinliğinde olabilmesidir. python-dotenv, bir ana dizinde en yakın olanı bulur ve onu kullanır. Bu yaklaşım için bir +2, jupyter'ın başlangıçta .env dosyasından ortam değişkenlerini yüklemesidir. Çifte nazar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.