Импорт модуля из относительного пути
как импортировать модуль Python с учетом его относительного пути?
например, если dirFoo содержит Foo.py и dirBar и dirBar содержит Bar.py, как я могу импортировать Bar.py на Foo.py?
вот визуальное представление:
dirFoo
Foo.py
dirBar
Bar.py
Foo желает включить Bar, но реструктуризация иерархии папок не является вариантом.
23 ответов:
предполагая, что оба ваших каталога являются реальными пакетами Python (есть
__init__.pyfile inside them), вот безопасное решение для включения модулей относительно местоположения скрипта.Я предполагаю, что вы хотите сделать это, потому что вам нужно включить набор модулей с вашим скриптом. Я использую это в производстве в нескольких продуктах и работает во многих специальных сценариях, таких как: скрипты, вызываемые из другого каталога или выполняемые с помощью python execute вместо открытия новый переводчик.
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 использовать ваш модуль вместо установленных в системе.
предупреждение! Я не знаю, что происходит, когда текущий модуль находится внутри . Это, вероятно, тоже не удается.
вы также можете добавить подкаталог в свой путь 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в комментарии Тома, это требует, чтобы
srcпапка доступна либо черезsite_packagesили ваш путь поиска. Кроме того, как он упоминает,__init__.pyнеявно импортируется при первом импорте модуля в этот пакет / каталог. Обычно__init__.py- это просто пустой файл.
самый простой способ-использовать sys.путь.добавлять.)(
однако, вы также можете быть заинтересованы в ИМП модуль. Он обеспечивает доступ к внутренним функциям импорта.
# 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...
In dirFoo\Foo.py:
from ..dirBar import Bar
самый простой способ без каких-либо изменений в вашем скрипте-установить переменную среды PYTHONPATH. Потому что sys.путь инициализируется из этих мест:
- каталог, содержащий входной скрипт (или текущий справочник.)
- PYTHONPATH (список имен каталогов, с тем же синтаксис как путь переменной оболочки).
- установка зависит от значения по умолчанию.
просто запустите:
export PYTHONPATH=/absolute/path/to/your/moduleвы sys.путь содержит выше путь, как показано ниже:
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 *Не рекомендуется использовать sys.путь.добавить () потому что что-то может пойти не так, если вы используете то же имя файла, что и существующий пакет python. Я не проверял это, но это будет неоднозначно.
быстрый-и-грязный способ для пользователей Linux
если вы просто возитесь и не заботитесь о проблемах развертывания, вы можете использовать символическую ссылку (при условии, что ваша файловая система поддерживает ее), чтобы сделать модуль или пакет непосредственно видимыми в папке запрашивающего модуля.
ln -s (path)/module_name.pyили
ln -s (path)/package_name
Примечание: "модуль" - это любой файл с расширением .py, а" пакет " - любая папка, содержащая файл
__init__.py(который может быть пустой файл.) С точки зрения использования модули и пакеты идентичны - оба раскрывают содержащиеся в них "определения и операторы", как это требуется через .
from .dirBar import Barвместо:
from dirBar import Barна всякий случай может быть установлен другой дирбар и запутать a foo.py читатель.
для этого случая импортировать Bar.py в Foo.py, сначала я бы превратил эти папки в пакеты Python следующим образом:
dirFoo\ __init__.py Foo.py dirBar\ __init__.py Bar.pyтогда я бы сделал это так Foo.py:
from .dirBar import BarЕсли бы я хотел, чтобы пространство имен выглядело как бар.все или
from . import dirBarЕсли бы я хотел пространство имен dirBar.Бар.все. Этот второй случай полезен, если у вас есть больше модулей под пакетом dirBar.
добавить __init__.py file:
dirFoo\ Foo.py dirBar\ __init__.py Bar.pyзатем добавьте этот код в начало Foo.py:
import sys sys.path.append('dirBar') import Bar
относительное представление sys.пример пути:
# /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, так что вы убедитесь, что все идет нормально. Этот способ всегда работает, потому что по определению Pythonsys.pathкак инициализировать по запуск программы, Первый пункт этого списка,path[0], это каталог, содержащий сценарий, который был использован для вызова интерпретатора Python.если каталог скриптов недоступен (например, если интерпретатор вызывается интерактивно или если скрипт считывается со стандартного ввода),
path[0]это пустая строка, которая направляет Python для поиска модулей в текущем каталоге в первую очередь. Обратите внимание, что каталог сценария вставляется перед записями, вставленными в результатеPYTHONPATH.
другим решением было бы установить py-require пакет, а затем использовать следующее в
Foo.pyimport require Bar = require('./dirBar/Bar')
посмотрите на модуль pkgutil из стандартной библиотеки. Это может помочь вам сделать то, что вы хотите.
вот способ импортировать файл с одного уровня выше, используя относительный путь.
в принципе, просто переместите рабочий каталог на уровень (или любое относительное местоположение), добавьте его в свой путь, а затем переместите рабочий каталог туда, где он начался.
#to import from one level above: cwd = os.getcwd() os.chdir("..") below_path = os.getcwd() sys.path.append(below_path) os.chdir(cwd)
просто вы можете использовать:
from Desktop.filename import somethingпример:
учитывая, что файл имеет имя
test.pyв каталогеUsers/user/Desktopи импортировать все.код:
from Desktop.test import *но убедитесь, что вы делаете пустой файл с именем"
__init__.py" в этот каталог
у меня нет опыта работы с python, поэтому, если в моих словах что-то не так, просто скажите мне. Если ваша файловая иерархия устроена следующим образом:
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, интерпретатор python скажетNo module named '__main__.module_1'; '__main__' is not a package. Чтобы исправить это, мы просто сохраните изменения, которые мы только что сделали, и переместите оба модуля в пакет, и сделайте третий модуль в качестве вызывающего для запускаmodule_2.py.project\ package_1\ module_1.py module_2.py main.pymain.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, интерпретатор python скажетNo module named 'module_1', это немного сложнее,module_1.pyнаходится рядом сmodule_2.py. Теперь я позволюfunc_1()наmodule_1.pydo что-то: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я думаю, что это совпадает с принципом упорядочения иерархии файлов проекта, вы должны расположить модули с разными функциями в разных папках и просто оставить верхний вызывающий объект снаружи, и вы можно импортировать как угодно.
Это также работает, и гораздо проще, чем все, что с
sysмодуль:with open("C:/yourpath/foobar.py") as f: eval(f.read())
Назовите меня чрезмерно осторожным, но мне нравится делать мой более портативным, потому что небезопасно предполагать, что файлы всегда будут в одном и том же месте на каждом компьютере. Лично у меня есть код, который сначала ищет путь к файлу. Я использую 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!")это, конечно, если вы не планируете, чтобы упаковать их вместе. Но если это так, вам все равно не нужны два отдельных файла.
Comments