Импортировать модуль из относительного пути
706 Jude Allred [2008-11-11 00:28:00]
Как импортировать модуль Python с учетом его относительного пути?
Например, если dirFoo
содержит Foo.py
и dirBar
, а dirBar
содержит Bar.py
, как мне импортировать Bar.py
в Foo.py
?
Здесь визуальное представление:
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
хочет включить Bar
, но перестройка иерархии папок не является вариантом.
python relative-path python-import
23 ответа
314 Решение sorin [2011-05-23 17:00:00]
Предполагая, что оба ваших каталога являются реальными пакетами Python (у них есть файл __init__.py
внутри них), вот безопасное решение для включения модулей относительно местоположения script.
Я предполагаю, что вы хотите сделать это, потому что вам нужно включить набор модулей с помощью script. Я использую это в производстве в нескольких продуктах и работает во многих специальных сценариях, таких как скрипты, вызванные из другого каталога или исполняемые с помощью 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
. Вероятно, он тоже не работает.
317 S.Lott [2008-11-11 00:33:00]
Убедитесь, что dirBar имеет файл __init__.py
- это делает каталог в пакете Python.
245 Andrew Cox [2008-11-11 01:04:00]
Вы также можете добавить подкаталог в свой путь Python, чтобы он импортировал как обычный скрипт.
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
110 lefakir [2010-11-26 13:21:00]
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
94 Deepak 'Kaseriya' [2010-12-09 13:40:00]
Просто делайте простые вещи, чтобы импортировать файл .py из другой папки.
Скажем, у вас есть каталог вроде:
lib/abc.py
Затем просто сохраните пустой файл в папке с именем
__init__.py
И затем используйте
from lib.abc import <Your Module name>
Храните файл __init__.py
в каждой папке иерархии модуля импорта.
77 bouvard [2008-11-11 00:46:00]
Если вы структурируете свой проект таким образом:
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 Tom это требует, чтобы папка src
была доступна либо через site_packages
, либо в вашем пути поиска. Кроме того, как он упоминает, __init__.py
неявно импортируется при первом импорте модуля в этот каталог/каталог. Обычно __init__.py
является просто пустым файлом.
44 monkut [2008-11-12 04:56:00]
Самый простой способ - использовать 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
Это можно использовать для динамического загрузки модулей, когда вы не знаете имя модуля.
Я использовал это в прошлом для создания интерфейса типа плагина для приложения, где пользователь записывал script с конкретными функциями приложения и просто отбрасывал script в определенном каталоге.
Кроме того, эти функции могут быть полезны:
imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)
41 Peter Crabtree [2008-11-11 01:22:00]
Это соответствующий PEP:
http://www.python.org/dev/peps/pep-0328/
В частности, предполагается, что dirFoo является каталогом из dirBar...
В dirFoo\Foo.py:
from ..dirBar import Bar
20 James Gan [2013-02-11 02:21:00]
Самый простой способ без каких-либо изменений в вашем script - установить переменную среды PYTHONPATH. Поскольку sys.path инициализируется из этих мест:
- Каталог, содержащий вход script (или текущий каталог).
- 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']
11 jhana [2010-09-15 08:02:00]
На мой взгляд, лучший выбор - поставить __ init __. py в папку и вызвать файл с помощью
from dirBar.Bar import *
Не рекомендуется использовать sys.path.append(), потому что что-то может пойти не так, если вы используете то же имя файла, что и существующий пакет python. Я не тестировал это, но это будет неоднозначно.
10 nobar [2012-12-20 04:07:00]
Быстрый и грязный способ для пользователей Linux
Если вы просто разбираетесь и не заботитесь о проблемах с развертыванием, вы можете использовать символическую ссылку (если ваша файловая система поддерживает ее), чтобы сделать модуль или пакет непосредственно видимыми в папке запрашивающего модуля.
ln -s (path)/module_name.py
или
ln -s (path)/package_name
Примечание. "Модуль" - это любой файл с расширением .py, а "пакет" - любая папка, содержащая файл __init__.py
(который может быть пустым файлом). С точки зрения использования модули и пакеты идентичны - оба раскрывают свои содержащиеся "определения и утверждения" по запросу с помощью команды import
.
9 jgomo3 [2011-08-31 23:02:00]
from .dirBar import Bar
вместо:
from dirBar import Bar
на всякий случай, если может быть установлен другой dirBar и запутать foo.py reader.
7 Al Conrad [2014-10-29 22:49:00]
Для этого случая, чтобы импортировать Bar.py в Foo.py, сначала я бы превратил эти папки в пакеты Python следующим образом:
dirFoo\
__init__.py
Foo.py
dirBar\
__init__.py
Bar.py
Тогда я сделал бы это так в Foo.py:
from .dirBar import Bar
Если бы я хотел, чтобы пространство имен выглядело как Bar.whatever, или
from . import dirBar
Если бы я хотел, чтобы namespacing dirBar.Bar.whatever. Этот второй случай полезен, если в пакете dirBar имеется больше модулей.
6 Josh [2010-02-28 23:34:00]
Добавьте файл __ init __. py:
dirFoo\
Foo.py
dirBar\
__init__.py
Bar.py
Затем добавьте этот код в начало Foo.py:
import sys
sys.path.append('dirBar')
import Bar
5 Der_Meister [2014-07-29 10:27:00]
Относительный пример 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
На основе этого ответа.
4 Avenida Gez [2015-04-02 01:29:00]
Ну, как вы заметили, обычно вы хотите иметь доступ к папке с вашими модулями относительно того, где выполняется ваш основной script, поэтому вы просто импортируете их.
Решение:
У меня есть script в 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
Поместите a print('done')
в oldies.py
, чтобы вы все проверили. Этот способ всегда работает, потому что по определению Python sys.path
, инициализированному при запуске программы, первым элементом этого списка path[0]
является каталог, содержащий script, который использовался для вызова интерпретатора Python.
Если каталог script недоступен (например, если интерпретатор вызывается в интерактивном режиме или если script считывается со стандартного ввода), path[0]
- это пустая строка, которая направляет Python на поиск модулей в текущем сначала. Обратите внимание, что каталог script вставлен перед вставками в результате PYTHONPATH
.
3 Niklas R [2016-08-07 00:26:00]
Другим решением было бы установить пакет py-require, а затем использовать в Foo.py
import require
Bar = require('./dirBar/Bar')
2 Mihail Mihaylov [2011-02-09 18:19:00]
Посмотрите на модуль pkgutil из стандартной библиотеки. Это может помочь вам сделать то, что вы хотите.
2 0x1996 [2018-01-26 22:30:00]
Просто вы можете использовать: from Desktop.filename import something
Пример:
учитывая, что файл является именем
test.py
в каталогеUsers/user/Desktop
и будет импортировать все.
код:
from Desktop.test import *
Но убедитесь, что вы создали пустой файл с именем " __init__.py
" в этом каталоге
2 Justin Muller [2012-01-27 20:43:00]
Здесь можно импортировать файл с одного уровня выше, используя относительный путь.
В основном, просто переместите рабочий каталог на уровень (или любое относительное местоположение), добавьте его в свой путь, затем переместите рабочий каталог туда, где он был запущен.
#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path = os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
0 OmouYue [2017-11-09 17:38:00]
Я не знаю о питоне, поэтому, если в моих словах что-то не так, просто скажите мне. Если иерархия файлов организована следующим образом:
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.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
, интерпретатор python скажет 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
Я думаю, что это совпадает с принципом организации иерархии файлов проекта, вы должны организовывать модули с различной функцией в разных папках и просто оставлять верхний вызывающий объект снаружи, и вы можете импортировать, как вы хотите.
0 jgilley [2018-07-25 23:23:00]
Это также работает и намного проще, чем что-либо с модулем sys
:
with open("C:/yourpath/foobar.py") as f:
eval(f.read())
-14 SuperFamousGuy [2011-09-22 22:33:00]
Позвоните мне слишком осторожно, но мне нравится делать мой более портативным, потому что небезопасно предполагать, что файлы всегда будут на одном месте на каждом компьютере. Лично у меня есть код, который сначала ищет путь к файлу. Я использую 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!")
Это, конечно, если вы не планируете их упаковывать вместе. Но в этом случае вам действительно не нужны два отдельных файла.