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/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,"..")
— 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.