상대 경로에서 모듈 가져 오기
상대 경로가 주어진 Python 모듈을 어떻게 가져 옵니까?
예를 들어, dirFoo
포함 Foo.py
및 dirBar
, 및 dirBar
포함 Bar.py
, 내가 어떻게 가져 옵니까 Bar.py
에 Foo.py
?
다음은 시각적 표현입니다.
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
를 포함 Bar
하고 싶지만 폴더 계층 구조를 재구성하는 것은 옵션이 아닙니다.
두 디렉토리가 모두 실제 Python 패키지 ( __init__.py
내부 에 파일이 있음) 라고 가정하면 스크립트 위치에 상대적으로 모듈을 포함하는 안전한 솔루션이 있습니다.
스크립트에 모듈 세트를 포함해야하므로이 작업을 원한다고 가정합니다. 나는 이것을 여러 제품의 프로덕션에서 사용하고 다른 디렉토리에서 호출되거나 새로운 인터프리터를 여는 대신 Python으로 실행되는 스크립트와 같은 많은 특수 시나리오에서 작동합니다.
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
파일 안에있을 때 무슨 일이 일어나는지 잘 모르겠습니다 . 아마도 실패 할 것입니다.
dirBar에 __init__.py
파일이 있는지 확인하십시오. 이것은 디렉토리를 Python 패키지로 만듭니다.
일반 스크립트로 가져 오도록 Python 경로에 하위 디렉토리를 추가 할 수도 있습니다.
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
다른 폴더에서 .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
으로 단순히 빈 파일입니다.
가장 쉬운 방법은 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는 다음 위치에서 초기화되기 때문입니다.
- 입력 스크립트가 포함 된 디렉토리 (또는 현재 디렉토리)입니다.
- PYTHONPATH (쉘 변수 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']
In my opinion the best choice is to put __ init __.py in the folder and call the file with
from dirBar.Bar import *
It is not recommended to use sys.path.append() because something might gone wrong if you use the same file name as the existing python package. I haven't test that but that will be ambiguous.
The quick-and-dirty way for Linux users
If you are just tinkering around and don't care about deployment issues, you can use a symbolic link (assuming your filesystem supports it) to make the module or package directly visible in the folder of the requesting module.
ln -s (path)/module_name.py
or
ln -s (path)/package_name
Note: A "module" is any file with a .py extension and a "package" is any folder that contains the file __init__.py
(which can be an empty file). From a usage standpoint, modules and packages are identical -- both expose their contained "definitions and statements" as requested via the import
command.
See: http://docs.python.org/2/tutorial/modules.html
from .dirBar import Bar
instead of:
from dirBar import Bar
just in case there could be another dirBar installed and confuse a foo.py reader.
For this case to import Bar.py into Foo.py, first I'd turn these folders into Python packages like so:
dirFoo\
__init__.py
Foo.py
dirBar\
__init__.py
Bar.py
Then I would do it like this in Foo.py:
from .dirBar import Bar
If I wanted the namespacing to look like Bar.whatever, or
from . import dirBar
If I wanted the namespacing dirBar.Bar.whatever. This second case is useful if you have more modules under the dirBar package.
Add an __init__.py file:
dirFoo\
Foo.py
dirBar\
__init__.py
Bar.py
Then add this code to the start of Foo.py:
import sys
sys.path.append('dirBar')
import Bar
Relative sys.path example:
# /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
Based on this answer.
Well, as you mention, usually you want to have access to a folder with your modules relative to where your main script is run, so you just import them.
Solution:
I have the script in D:/Books/MyBooks.py
and some modules (like oldies.py). I need to import from subdirectory D:/Books/includes
:
import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path) # Just verify it is there
import oldies
Place a print('done')
in oldies.py
, so you verify everything is going OK. This way always works because by the Python definition sys.path
as initialized upon program startup, the first item of this list, path[0]
, is the directory containing the script that was used to invoke the Python interpreter.
If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0]
is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH
.
Another solution would be to install the py-require package and then use the following in Foo.py
import require
Bar = require('./dirBar/Bar')
Simply you can use: from Desktop.filename import something
Example:
given that the file is name
test.py
in directoryUsers/user/Desktop
, and will import everthing.
the code:
from Desktop.test import *
But make sure you make an empty file called "__init__.py
" in that directory
Here's a way to import a file from one level above, using the relative path.
Basically, just move the working directory up a level (or any relative location), add that to your path, then move the working directory back where it started.
#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path = os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
I'm not experienced about python, so if there is any wrong in my words, just tell me. If your file hierarchy arranged like this:
project\
module_1.py
module_2.py
module_1.py
defines a function called func_1()
, module_2.py:
from module_1 import func_1
def func_2():
func_1()
if __name__ == '__main__':
func_2()
and you run python module_2.py
in cmd, it will do run what func_1()
defines. That's usually how we import same hierarchy files. But when you write from .module_1 import func_1
in module_2.py
, python interpreter will say No module named '__main__.module_1'; '__main__' is not a package
. So to fix this, we just keep the change we just make, and move both of the module to a package, and make a third module as a caller to run 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()
But the reason we add a .
before module_1
in module_2.py
is that if we don't do that and run main.py
, python interpreter will say No module named 'module_1'
, that's a little tricky, module_1.py
is right beside module_2.py
. Now I let func_1()
in module_1.py
do something:
def func_1():
print(__name__)
that __name__
records who calls func_1. Now we keep the .
before module_1
, run main.py
, it will print package_1.module_1
, not module_1
. It indicates that the one who calls func_1()
is at the same hierarchy as main.py
, the .
imply that module_1
is at the same hierarchy as module_2.py
itself. So if there isn't a dot, main.py
will recognize module_1
at the same hierarchy as itself, it can recognize package_1
, but not what "under" it.
Now let's make it a bit complicated. You have a config.ini
and a module defines a function to read it at the same hierarchy as 'main.py'.
project\
package_1\
module_1.py
module_2.py
config.py
config.ini
main.py
And for some unavoidable reason, you have to call it with module_2.py
, so it has to import from upper hierarchy.module_2.py:
import ..config
pass
Two dots means import from upper hierarchy (three dots access upper than upper,and so on). Now we run main.py
, the interpreter will say:ValueError:attempted relative import beyond top-level package
. The "top-level package" at here is main.py
. Just because config.py
is beside main.py
, they are at same hierarchy, config.py
isn't "under" main.py
, or it isn't "leaded" by main.py
, so it is beyond main.py
. To fix this, the simplest way is:
project\
package_1\
module_1.py
module_2.py
config.py
config.ini
main.py
I think that is coincide with the principle of arrange project file hierarchy, you should arrange modules with different function in different folders, and just leave a top caller in the outside, and you can import how ever you want.
This also works, and is much simpler than anything with the sys
module:
with open("C:/yourpath/foobar.py") as f:
eval(f.read())
Call me overly cautious, but I like to make mine more portable because it's unsafe to assume that files will always be in the same place on every computer. Personally I have the code look up the file path first. I use Linux so mine would look like this:
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!")
That is of course unless you plan to package these together. But if that's the case you don't really need two separate files anyway.
참고URL : https://stackoverflow.com/questions/279237/import-a-module-from-a-relative-path
'Program Tip' 카테고리의 다른 글
유닉스 타임 스탬프 문자열을 읽을 수있는 날짜로 변환 (0) | 2020.09.29 |
---|---|
특수 달러 기호 쉘 변수는 무엇입니까? (0) | 2020.09.29 |
문자열이 유효한 URL인지 확인하는 가장 좋은 정규 표현식은 무엇입니까? (0) | 2020.09.29 |
정확히 8192 개 요소를 반복 할 때 내 프로그램이 느린 이유는 무엇입니까? (0) | 2020.09.29 |
** kwargs의 목적과 사용은 무엇입니까? (0) | 2020.09.29 |