Python 3을 사용하여 Jupyter Notebook의 상대적 가져 오기와 함께 다른 디렉토리에있는 모듈에서 로컬 함수 가져 오기


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파일 (빈 파일 포함)을 포함해야하는 경우 괜찮지 만 그렇게하는 것만으로는 문제를 해결할 수 없습니다.

나는이 디렉토리를 기계들간에 공유하고 상대 가져 오기를 통해 어디서나 동일한 코드를 사용할 수 있으며 빠른 프로토 타이핑을 위해 노트북을 자주 사용하므로 절대 경로를 함께 해킹하는 것과 관련된 제안은 도움이되지 않을 것입니다.


편집 : 이것은 일반적으로 Python 3의 상대적 가져 오기, 특히 패키지 디렉토리 내에서 스크립트 실행에 대해 말하는 Python 3의 상대 가져 오기 와 다릅니다 . 이것은 일반적인 측면과 특정 측면이 모두 다른 다른 디렉토리의 로컬 모듈에서 함수를 호출하려는 jupyter 노트북 내에서 작업하는 것과 관련이 있습니다.


1
어떤이 __init__패키지 디렉토리에있는 파일은?
Iron Fist

예, lib디렉토리에 있습니다.
mpacer 2015

, 귀하의 질문에 디렉토리 구조에서 그것을 언급 마십시오
철권에게

첫 번째 댓글을 보자 마자 수정했습니다. :). 잡아 주셔서 감사합니다.
mpacer 2015

답변:


174

인접한 모듈의 기능을 DRY 방식으로 사용하는 방법을 설명하고자하는 이 노트북 에서 여러분과 거의 같은 예를 들었습니다 .

내 솔루션은 노트북에 다음과 같은 스 니펫을 추가하여 Python에 추가 모듈 가져 오기 경로를 알리는 것입니다.

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

비어있는 __init__.py파일이 아직없는 경우 project1 /lib / 폴더 에 추가 해야합니다.


6
이것은 상대적인 위치를 사용하여 패키지를 가져올 수있는 문제를 해결하지만 간접적으로 만 가능합니다. 나는 Matthias Bussonier (@matt on SE)와 Yuvi Panda (@yuvi on SE)가 github.com/ipython/ipynb 를 개발하고 있다는 것을 알게되었습니다. 가져옴). 나는 지금 당신의 대답을 받아 들일 것이며, 그들의 솔루션이 다른 사람들이 사용할 수 있도록 완전히 준비되면 아마도 그것을 사용하는 방법에 대한 대답을 쓰거나 그들 중 한 사람에게 그렇게하도록 요청할 것입니다.
mpacer

init .py 를 지적 해 주셔서 감사합니다. 저는 파이썬 초보자이며 수업을 가져 오는 데 문제가있었습니다. 모듈 노트 발견 오류가 발생하여 빈 init .py를 추가 하면 문제가 해결되었습니다!
Pat Grady 2017

5
초기화 평 파일은 더 이상 파이썬 3에서 필요하지 않습니다
CathyQian

참고 : 노트북 용 뷰어가 있습니다 : nbviewer.jupyter.org/github/qPRC/qPRC/blob/master/notebook/…
thoroc

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

이는 기본적으로 Jupyter Notebook이 cd명령을 구문 분석 할 수 있기 때문에 작동합니다 . 이것은 Python Notebook 마법을 사용하지 않습니다. 그것은 단순히 접두사없이 작동합니다 %bash.

Project Jupyter Docker 이미지 중 하나를 사용하여 Docker에서 작업하고있는 100 번 중 99 번을 고려 하면 다음 수정 멱등 적입니다.

    In [1]: cd /home/jovyan

    In [2]: from lib.postgres import database_connection

감사. 이 상대적 수입품의 제한은 정말 끔찍합니다.
마이클

나도 chdir경로에 추가 하는 대신 사용 합니다. 왜냐하면 메인 저장소에서 가져 오는 것과 거기에있는 일부 파일과의 인터페이스에 관심이 있기 때문입니다.
TheGrimmScientist

슬프게도 내가 파이썬에서 가장 많이 해킹 한 일이다. 그러나 더 나은 해결책을 찾을 수 없습니다.
TheGrimmScientist

간단한 멱 등성을 위해 (동일한 셀이 여러 번 실행되고 동일한 결과를 얻을 수 있음) : if os.path.isdir('../lib/'): os.chdir('../lib'); 또는 더 나은 방법 ../lib/db/postgres.py실수로 다른 lib.
michael

1
실수로 cd ..두 번 실행하기 전까지는이 솔루션이 마음에 듭니다.
minhle_r7

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/explorenotebooks/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,"..")
Yaakov Bressler

2

이 주제를 직접 조사하고 답변을 읽은 후 현재 작업 디렉토리를 변경하기위한 컨텍스트 관리자를 제공하므로 path.py 라이브러리를 사용하는 것이 좋습니다 .

그런 다음

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

하지만이 isdir문장을 생략 할 수도 있습니다 .

여기에 무슨 일이 일어나고 있는지 쉽게 알 수 있도록 print 문을 추가하겠습니다.

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

이 예제에서 출력되는 내용은 다음과 같습니다 (lib가에 있음 /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

솔루션이 컨텍스트 관리자를 사용하기 때문에 셀 이전의 커널 상태와 라이브러리 코드를 가져 와서 발생하는 예외에 관계없이 이전 작업 디렉토리로 돌아갈 수 있습니다.


모듈 경로를 다시로드 할 때 찾을 수 없기 때문에 % autoreload와 함께 작동하지 않습니다
Johannes

1

여기 내 2 센트 :

수입 시스템

모듈 파일이있는 경로를 매핑합니다. 제 경우에는 데스크탑이었습니다

sys.path.append ( '/ Users / John / Desktop')

전체 매핑 모듈을 가져 오지만 .notation을 사용하여 mapping.Shipping ()과 같은 클래스를 매핑해야합니다.

import mapping # mapping.py는 내 모듈 파일의 이름입니다.

shipit = mapping.Shipment () #Shipment는 매핑 모듈에서 사용해야하는 클래스의 이름입니다.

또는 매핑 모듈에서 특정 클래스를 가져옵니다.

매핑 가져 오기 매핑에서

shipit = Shipment () # 이제 .notation을 사용할 필요가 없습니다.


0

python-dotenv 가이 문제를 매우 효과적으로 해결하는 데 도움이 된다는 것을 발견했습니다 . 프로젝트 구조가 약간 변경되지만 노트북의 코드는 노트북에서 약간 더 간단하고 일관됩니다.

프로젝트의 경우 약간의 설치를 수행하십시오.

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은 노트북이 여러 디렉토리 깊이 일 수 있다는 것입니다. python-dotenv는 상위 디렉토리에서 가장 가까운 디렉토리를 찾아서 사용합니다. 이 접근 방식의 +2는 jupyter가 시작시 .env 파일에서 환경 변수를로드한다는 것입니다. 더블 whammy.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.