상대 경로가 주어진 파이썬 모듈을 어떻게 가져 옵니까?
예를 들어, dirFoo
포함 Foo.py
및 dirBar
, 및 dirBar
포함 Bar.py
, 내가 어떻게 가져 옵니까 Bar.py
에 Foo.py
?
시각적 인 표현은 다음과 같습니다.
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
포함 Bar
하고 싶지만 폴더 계층 구조를 재구성하는 것은 옵션이 아닙니다.
상대 경로가 주어진 파이썬 모듈을 어떻게 가져 옵니까?
예를 들어, dirFoo
포함 Foo.py
및 dirBar
, 및 dirBar
포함 Bar.py
, 내가 어떻게 가져 옵니까 Bar.py
에 Foo.py
?
시각적 인 표현은 다음과 같습니다.
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
포함 Bar
하고 싶지만 폴더 계층 구조를 재구성하는 것은 옵션이 아닙니다.
답변:
두 디렉토리가 모두 실제 파이썬 패키지라고 가정하면 ( __init__.py
파일 안에 파일이 있음) 스크립트의 위치에 상대적으로 모듈을 포함시키는 안전한 솔루션이 있습니다.
스크립트에 모듈 세트를 포함해야하므로이 작업을 원한다고 가정합니다. 나는 이것을 여러 제품의 프로덕션에서 사용하고 다른 디렉토리에서 호출되거나 새로운 인터프리터를 여는 대신 파이썬 실행으로 실행되는 스크립트와 같은 많은 특수 시나리오에서 작동합니다.
import os, sys, inspect
# realpath() will make your script run, even if you symlink it :)
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
# Use this if you want to include modules from a subfolder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
# Info:
# cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
# __file__ fails if the script is called in different ways on Windows.
# __file__ fails if someone does os.chdir() before.
# sys.argv[0] also fails, because it doesn't not always contains the path.
또한이 방법을 사용하면 Python이 시스템에 설치된 모듈 대신 모듈을 사용하도록 할 수 있습니다.
경고! 현재 모듈이 egg
파일 안에있을 때 무슨 일이 일어나고 있는지 잘 모르겠습니다 . 아마도 실패 할 것입니다.
os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")
하지 마십시오abspath
. 심각한 버그가 발생할 수 있습니다.
cmd_subfolder
)를 내 답변에 직접 추가 할 수 있습니다 . 감사!
realpath
이미 절대 경로를 생성하므로 필요하지 않습니다 abspath
. 또한 os.path.dirname
색인이 makeing, 대신 분할 사용할 수 있습니다 [0]
되지 않습니다. 라인은 다음과 같습니다.os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
dirBar에 __init__.py
파일이 있는지 확인하십시오. 그러면 디렉토리가 Python 패키지로 만들어집니다.
sys.path
다음의 존재 __init__.py
의 dirBar
디렉토리에 큰 도움이되지 않습니다.
__init.py__
는 디렉토리가 이미 sys.path에 있고 제 경우에는 그렇지 않은 경우에만 작동합니다. "sorin"(허용되는)에 의한 솔루션은 항상 작동합니다.
sys.path
질문 에 있지 않다는 것을 어떻게 추측 할 수 있습니까? 우리가 보거나 알지 못했던 부분이 있었을 수도 있습니다.
하위 디렉토리를 Python 경로에 추가하여 일반 스크립트로 가져올 수 있습니다.
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
sys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
sys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
sys.path.insert(0, <path to dirFoo>)
다른 곳에 저장된 동일한 이름의 모듈보다 먼저이 모듈을로드하므로 사용 을 고려하십시오 .
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
os.path.join()
'/'로 연결 하는 대신 (lame) 창에서 중단되는 대신 사용해야합니다 .
os.path.abspath(os.path.join(__file__,'..','lib'))
.
다른 폴더에서 .py 파일을 가져 오는 간단한 작업을 수행하십시오.
다음과 같은 디렉토리가 있다고 가정 해 봅시다.
lib/abc.py
그런 다음 이름이 지정된 것처럼 lib 폴더에 빈 파일을 유지하십시오.
__init__.py
그런 다음 사용
from lib.abc import <Your Module name>
__init__.py
가져 오기 모듈 계층의 모든 폴더에 파일을 보관하십시오 .
이런 식으로 프로젝트를 구성하는 경우 :
src\
__init__.py
main.py
dirFoo\
__init__.py
Foo.py
dirBar\
__init__.py
Bar.py
그런 다음 Foo.py에서 다음을 수행 할 수 있습니다.
import dirFoo.Foo
또는:
from dirFoo.Foo import FooObject
Tom의 의견에 따르면 src
폴더를 통해 site_packages
또는 검색 경로 를 통해 폴더에 액세스 할 수 있어야합니다 . 또한 언급했듯이 __init__.py
해당 패키지 / 디렉토리에서 모듈을 처음 가져올 때 암시 적으로 가져옵니다. 일반적으로 __init__.py
빈 파일입니다.
from dirFoo import Foo
대답 Foo.bla()
. import dirFoo.Foo
하나를 사용 하면 dirFoo.Foo.bla()
낙타 케이스가 없어도 아주 못생긴 것을 사용해야합니다 .
가장 쉬운 방법은 sys.path.append ()를 사용하는 것입니다.
그러나 imp 모듈 에도 관심이있을 수 있습니다 . 내부 가져 오기 기능에 대한 액세스를 제공합니다.
# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file
모듈 이름을 모르는 경우 모듈을 동적으로로드하는 데 사용할 수 있습니다.
과거에는 이것을 사용하여 응용 프로그램에 대한 플러그인 유형 인터페이스를 만들었습니다. 여기서 사용자는 응용 프로그램 특정 기능으로 스크립트를 작성하고 특정 디렉토리에 해당 스크립트를 드롭합니다.
또한 이러한 기능이 유용 할 수 있습니다.
imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)
이것은 관련 PEP입니다.
http://www.python.org/dev/peps/pep-0328/
특히 dirFoo는 dirBar의 디렉토리입니다.
dirFoo \ Foo.py에서 :
from ..dirBar import Bar
스크립트를 수정하지 않고 가장 쉬운 방법은 PYTHONPATH 환경 변수를 설정하는 것입니다. sys.path는 다음 위치에서 초기화되기 때문에 :
그냥 실행 :
export PYTHONPATH=/absolute/path/to/your/module
sys.path에는 아래와 같이 위의 경로가 포함됩니다.
print sys.path
['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
내 의견으로는 최선의 선택은 폴더 에 __ init __.py 를 넣고 파일을 호출하는 것입니다.
from dirBar.Bar import *
기존 python 패키지와 동일한 파일 이름을 사용하면 문제가 발생할 수 있으므로 sys.path.append ()를 사용하지 않는 것이 좋습니다. 나는 그것을 테스트하지 않았지만 모호 할 것입니다.
from dirBar.Bar import *
하지만 작동하지 않습니다 from dirBar.Bar import Bar
. 왜 작동하는지 아십니까? dirBar /에 여러 파일이 있고 여기에 게시 한 것과 같은 방법을 사용하여 파일 중 일부만 가져 오려면 어떻게해야합니까?
from dirBar import Bar
.
from
는 소스를 나타 내기 때문에 그 이후의 모든 것이 소스에서 import
가져옵니다. from dirBar.Bar import Bar
"소스에서 소스 자체를 가져 오십시오"를 의미합니다. *
하지만 수단은 "나에게 소스에서 모든 것을 제공"
문제를 해결하고 배포 문제에 신경 쓰지 않는다면 심볼릭 링크 (파일 시스템이 지원한다고 가정)를 사용하여 요청 모듈의 폴더에 모듈 또는 패키지를 직접 볼 수 있습니다.
ln -s (path)/module_name.py
또는
ln -s (path)/package_name
참고 : "모듈"은 확장명이 .py 인 파일이고 "패키지"는 파일이 들어있는 폴더입니다 __init__.py
(빈 파일 일 수 있음). 사용 관점에서 모듈과 패키지는 동일합니다. 둘 다를 통해 요청한대로 포함 된 "정의 및 진술"을 공개합니다import
. 명령을 .
from .dirBar import Bar
대신에:
from dirBar import Bar
다른 dirBar가 설치되어 foo.py 리더와 혼동 될 수있는 경우를 대비하여.
이 경우 Bar.py를 Foo.py로 가져 오려면 먼저이 폴더를 다음과 같이 Python 패키지로 바꿉니다.
dirFoo\
__init__.py
Foo.py
dirBar\
__init__.py
Bar.py
그런 다음 Foo.py에서 다음과 같이하십시오.
from .dirBar import Bar
이름 공간이 Bar처럼 보이기를 원한다면. 무엇이든 , 또는
from . import dirBar
네임 스페이스 dirBar.Bar를 원한다면. 무엇이든 . 이 두 번째 경우는 dirBar 패키지 아래에 더 많은 모듈이있는 경우 유용합니다.
상대 sys.path 예 :
# /lib/my_module.py
# /src/test.py
if __name__ == '__main__' and __package__ is None:
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module
언급했듯이 일반적으로 기본 스크립트가 실행되는 위치와 관련하여 모듈이있는 폴더에 액세스하려고하므로 가져 오기 만하면됩니다.
해결책:
스크립트 D:/Books/MyBooks.py
와 oldies.py와 같은 일부 모듈이 있습니다. 하위 디렉토리에서 가져와야합니다 D:/Books/includes
.
import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path) # Just verify it is there
import oldies
장소 print('done')
에를 oldies.py
당신이 모든 확인을 것입니다 확인, 그래서. 이 방법은 항상 작동합니다. 파이썬 정의 sys.path
에 의해이 목록의 첫 번째 항목 인 프로그램 시작시 초기화됩니다.path[0]
가 Python 인터프리터를 호출하는 데 사용 된 스크립트를 포함하는 디렉토리 .
스크립트 디렉토리를 사용할 수없는 경우 (예 : 인터프리터가 대화식으로 호출되거나 표준 입력에서 스크립트를 읽는 경우) path[0]
빈 문자열은 파이썬이 현재 디렉토리에서 모듈을 먼저 검색하도록 지시합니다. 스크립트 디렉토리는의 결과로 삽입 된 항목 앞에 삽입됩니다 PYTHONPATH
.
site.addsitedir(sys.path[0]+'/includes')
첫 번째 간단한 Python 프로그램 break_time.py : https://github.com/ltfschoen/PythonTest 에서 두 개의 백 슬래시 대신 하나의 슬래시 (예 :)를 사용해야했습니다 . 나는 시스템을 사용합니다 : MacOS v10.11.5, Python 2.7.12, 유휴 IDE 2.7.12, Tk 8.5.9
간단히 사용할 수 있습니다 : from Desktop.filename import something
예:
파일의 이름
test.py
이 directoryUsers/user/Desktop
에 있고 모든 것을 가져옵니다.
코드:
from Desktop.test import *
하지만 __init__.py
해당 디렉토리에 " " 라는 빈 파일을 만드십시오.
import something
말했다. *
또한 2 개의 함수가 같은 이름을 가지고 있다면 코드가
또 다른 해결책은 py-require 패키지 를 설치 하고 다음을 사용하는 것입니다.Foo.py
import require
Bar = require('./dirBar/Bar')
require()
기능이 필요한 경우 내 Node.py 프로젝트를 살펴볼 수 있습니다. github.com/nodepy/nodepy
다음은 상대 경로를 사용하여 한 수준에서 파일을 가져 오는 방법입니다.
기본적으로 작업 디렉토리를 특정 레벨 (또는 상대 위치) 위로 이동하고 경로에 추가 한 다음 작업 디렉토리를 시작 위치로 다시 이동하십시오.
#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path = os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
나는 파이썬에 대해 경험이 없기 때문에 내 말에 잘못이 있으면 알려주십시오. 파일 계층이 다음과 같이 배열 된 경우 :
project\
module_1.py
module_2.py
module_1.py
라는 함수를 정의 func_1()
, module_2.py을 :
from module_1 import func_1
def func_2():
func_1()
if __name__ == '__main__':
func_2()
python module_2.py
cmd에서 실행하면 func_1()
정의한 내용이 실행됩니다 . 일반적으로 동일한 계층 구조 파일을 가져 오는 방법입니다. 당신이 쓰는 때 from .module_1 import func_1
에 module_2.py
, 파이썬 인터프리터는 말할 것이다 No module named '__main__.module_1'; '__main__' is not a package
. 이 문제를 해결하기 위해 방금 변경 한 내용을 유지하고 두 모듈을 모두 패키지로 옮기고 세 번째 모듈을 호출자로 실행합니다.module_2.py
.
project\
package_1\
module_1.py
module_2.py
main.py
main.py :
from package_1.module_2 import func_2
def func_3():
func_2()
if __name__ == '__main__':
func_3()
그러나 우리가 .
이전 module_1
에 추가 한 이유는 module_2.py
우리가 그것을하지 않고 실행 main.py
하면 파이썬 인터프리터는 No module named 'module_1'
약간 까다 롭지 module_1.py
만 바로 옆에 있기 때문 module_2.py
입니다. 지금은하자 func_1()
에module_1.py
무언가를 :
def func_1():
print(__name__)
그 __name__
func_1을 호출 한 사람 기록합니다. 이제 우리는 .
이전 을 유지하고 module_1
실행 main.py
합니다 . 인쇄 package_1.module_1
하지 않습니다 module_1
. 이 호출 한 것을 나타냅니다 func_1()
같은 계층 구조에있다 main.py
(가), .
그 의미 module_1
와 같은 계층 구조에 있습니다 module_2.py
자체. 점이 없으면main.py
module_1
자체와 동일한 계층에서 인식 하여 인식 할 수 있습니다.package_1
있지만 무엇 "에서".
이제 조금 복잡하게합시다. 당신은config.ini
및 모듈에는 'main.py'와 동일한 계층 구조에서 읽는 함수를 정의합니다.
project\
package_1\
module_1.py
module_2.py
config.py
config.ini
main.py
그리고 불가피한 이유로,로 호출해야 module_2.py
하므로 상위 계층 구조에서 가져와야합니다. module_2.py :
import ..config
pass
두 개의 점은 상위 계층 구조에서 가져 오기를 의미합니다 (세 개의 점은 위보다 위쪽에 액세스하는 등). 이제 우리는 실행main.py
통역사가 과 같이 말합니다 ValueError:attempted relative import beyond top-level package
. 여기의 "최상위 패키지"는 main.py
입니다. config.py
옆에 있기 때문에 main.py
같은 계층 구조 에 있거나 config.py
"언더" main.py
가 아니거나 "리딩"되지 않기 main.py
때문에 넘어 main.py
있습니다. 이 문제를 해결하는 가장 간단한 방법은 다음과 같습니다.
project\
package_1\
module_1.py
module_2.py
config.py
config.ini
main.py
나는 그것이 프로젝트 파일 계층 구조를 정렬하는 원칙과 일치한다고 생각합니다. 다른 폴더에 다른 기능을 가진 모듈을 배열하고 외부에 최상위 호출자를 남겨두면 원하는 방식으로 가져올 수 있습니다.
지나치게 신중하게 전화하십시오. 그러나 파일이 항상 모든 컴퓨터에서 동일한 위치에 있다고 가정하는 것이 안전하지 않기 때문에 좀 더 휴대하기 편리합니다. 개인적으로 코드가 파일 경로를 먼저 찾도록합니다. Linux를 사용하므로 다음과 같이 보일 것입니다.
import os, sys
from subprocess import Popen, PIPE
try:
path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0]
if not sys.path.__contains__(path):
sys.path.append(path)
except IndexError:
raise RuntimeError("You must have FILE to run this program!")
물론 패키지를 함께 묶을 계획이 아니라면 말이다. 그러나 그렇다면 두 개의 별도 파일이 필요하지 않습니다.