Как импортировать модуль Python с учетом его относительного пути?
Например, если dirFoo содержит Foo.py и dirBar, а dirBar содержит Bar.py, как мне импортировать Bar.py в Foo.py?
Вот визуальное представление:
dirFoo\
Foo.py
dirBar\
Bar.py
Foo хочет включить Bar, но реструктуризация иерархии папок не вариант.
Проверьте мой ответ, он пока самый полный, другие не работают в особых случаях, например, когда вы вызываете скрипт из другого каталога или из другого скрипта python. См. stackoverflow.com/questions/279237/…
У меня была аналогичная проблема, я нашел это, и он работает !! apt-get установить python-profiler
На всякий случай, если кто-то захочет сделать это статически и попадет сюда (как я :), вы также можете настроить переменную среды PYTHONPATH
Лучше следовать инструкциям в Lib / site.py для каждого случая.






Убедитесь, что в dirBar есть файл __init__.py - это превращает каталог в пакет Python.
Обратите внимание, что этот файл может быть полностью пустым.
Если родительский каталог dirBar не находится в sys.path, то присутствие __init__.py в каталоге dirBar не очень помогает.
Приведенный выше комментарий предполагает, что dirBar является подпакетом.
-1, добавление __init.py__ будет работать только тогда, когда каталог уже находится в sys.path, а в моем случае это не так. Решение по «сорину» (принятое) всегда работает.
"когда каталог уже находится в sys.path". Хотя это абсолютно верно, как мы могли догадаться, что каталога не было в sys.path из вопроса? Возможно, было что-то упущено, чего мы не видели или о чем не знали?
Дополнительный контекст: __init__.py - это просто токен, который сообщает Python, что вы действительно хотите иметь возможность использовать папку с import (по умолчанию «нет», чтобы предотвратить случайное повреждение пространства имен).
Хотя это не обязательно идеальное решение во всех случаях, оно очень хорошо работает для таких целей, как организация модулей. Спасибо!
Это отнюдь не означает ответ на вопрос: существует ли файл инициализации или нет, это не заставляет python заглядывать в подкаталоги. Как он получил сотни положительных голосов?
Если вы структурируете свой проект таким образом:
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 - это просто пустой файл.
Также отметьте, что в этом.py импортируется, когда импортируется первый модуль внутри этого пакета. Кроме того, ваш пример будет работать только в том случае, если src находится в site_packages (или в пути поиска)
Это самое простое решение, которое я искал. Если файл для импорта обязательно находится в одном из подкаталогов, это решение - жемчужина.
Я пробовал то же самое, но потерпел неудачу. Я не знаю почему. ImportError: нет модуля с именем customMath
Зачем кому-то импортировать Foo из самого Foo.py? Думаю, должно быть от Bar.py.
from dirFoo import Foo, чтобы сказать Foo.bla(). При использовании import dirFoo.Foo следует использовать dirFoo.Foo.bla() - довольно некрасиво даже без верблюжьего футляра.
как импортировать Bar.py из Foo.py ??
Вы также можете добавить подкаталог в свой путь Python, чтобы он импортировался как обычный скрипт.
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
Похоже, ваш ответ не работает с относительными путями, см. stackoverflow.com/questions/279237/…
Этот делает работает с относительными путями - вам просто нужно понимать, что относительный путь будет зависеть от того, из какого каталога вы запускаете, что делает его плохим решением для чего-либо, кроме быстрого взлома.
Можно сделать что-то вроде 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>), поскольку он загрузит этот модуль раньше, чем одноименные модули, хранящиеся в другом месте.
Это соответствующий PEP:
http://www.python.org/dev/peps/pep-0328/
В частности, предположим, что dirFoo - это каталог выше dirBar ...
В dirFoo \ Foo.py:
from ..dirBar import Bar
это сработало для меня, просто добавил в этом.py в каждую папку и успешно импортировать
Самый простой способ - использовать sys.path.append ().
Однако вас также может заинтересовать модуль чертенок. Он обеспечивает доступ к функциям внутреннего импорта.
# 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)
Обратите внимание, что в документации imp.load_source и imp.load_compiled указаны как устаревшие. Вместо этого рекомендуется использовать imp.find_module и imp.load_module.
@amicitas, не могли бы вы предоставить какую-либо ссылку на это (мне это нужно, и я использую python 2.6. Я знаю, что об этом говорится в документации 2.7, но не нашел ссылки на 2.6)
@ 0xc0de Вы можете найти этот оператор в документации для модуля imp как для Python 2.7.3, так и для Python 2.6.7. Похоже, этих функций нет даже в документации для python 3.2.
Для импорта таких исходных файлов в python 3.3 см. Импортируйте произвольный исходный файл на Python. (Python 3.3+) - 2 ответа. Спасибо, ребята, за советы.
Добавьте файл __init__.py:
dirFoo\
Foo.py
dirBar\
__init__.py
Bar.py
Затем добавьте этот код в начало Foo.py:
import sys
sys.path.append('dirBar')
import Bar
Если dirBar уже является пакетом Python (из-за наличия dirBar/__init__.py), нет необходимости добавлять dirBar в sys.path, не так ли? Заявления import Bar от Foo.py должно хватить.
На мой взгляд, лучший выбор - поместить __ init __.py в папку и вызвать файл с
from dirBar.Bar import *
Не рекомендуется использовать sys.path.append (), потому что что-то может пойти не так, если вы используете то же имя файла, что и существующий пакет python. Я не тестировал это, но это будет неоднозначно.
странно, что from dirBar.Bar import * работает, но не from dirBar.Bar import Bar. ты знаешь почему * работает? что, если бы у меня было несколько файлов в dirBar / и я хотел бы получить только несколько из них (используя метод, подобный тому, который вы разместили здесь)?
@tester: используйте from dirBar import Bar.
@tester это потому, что from указывает источник, а все, что находится после import, - это то, что нужно взять из этого источника. from dirBar.Bar import Bar означает «Из источника импортировать сам источник», что не имеет смысла. * означает, что "дайте мне все от источника"
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
Мне это нравится, потому что у вас есть возможность подняться по каталогу.
Вы должны использовать os.path.join() вместо соединения с помощью '/', что приведет к поломке (хромых) окон.
Это ненадежно. Это зависит от текущего рабочего каталога, а не от каталога, в котором находится скрипт.
Может потребоваться добавить только в том случае, если путь еще не входит в путь. lib_path = os.path.abspath ('../ functions'), если lib_path не находится в sys.path: sys.path.append (lib_path)
в ответ на @jamesdlin, объединив несколько ответов: а как насчет os.path.abspath(os.path.join(__file__,'..','lib'))?
@MatthewDavis Я полагаю, что это работает, но мне кажется неправильным использовать имя файла в качестве такого каталога (а затем отбрасывать его с помощью ".."). Я лично предпочел бы сначала использовать os.path.dirname(__file__).
Честная оценка. Я вижу единственное преимущество подхода '..' - это сжатая цепочка: os.path.join(__file__, '..', '..', '..', 'lib') позволяет подняться на несколько уровней выше. Я полагаю, что наиболее понятным было бы: os.path.join(os.path.dirname(__file__), '..', '..', 'lib'), но это кажется излишним. Мысли?
Просто сделайте простые вещи, чтобы импортировать файл .py из другой папки.
Допустим, у вас есть такой каталог:
lib/abc.py
Затем просто сохраните пустой файл в папке lib с именем
__init__.py
А затем используйте
from lib.abc import <Your Module name>
Храните файл __init__.py в каждой папке иерархии модуля импорта.
Предполагая, что оба ваших каталога являются настоящими пакетами 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. Вероятно, это тоже не удается.
могу я получить объяснение, как это работает? У меня аналогичная проблема, и мне бы НРАВИТСЯ заставить модуль Python DIR вместо выполнения поиска
Запуская Win 7 Pro 64x и Python 2.7, я получаю несколько ошибок. 1) Мне пришлось добавить инспекцию в список импорта. 2) Первое значение [0] в кортеже - это пустая строка. Вторая, [1], показывает имя файла. Я предполагаю, что первым должен быть путь ... Есть идеи?
Если вы собираетесь использовать подпапку, используйте ее следующим образом: os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder") Добавьте НЕТ подпапку перед abspath, поскольку это вызывает серьезные ошибки.
@ scr4ve вместо этого вам следует использовать os.path.join (), и вы можете добавить регистр (cmd_subfolder) непосредственно к моему ответу. Благодарность!
для меня realpath уже генерирует абсолютные пути, поэтому мне не нужен abspath. Кроме того, вместо разделения можно использовать os.path.dirname, что делает индексирование [0] устаревшим. Тогда строка будет: os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
inspect.currentframe() - это «деталь реализации CPython» (docs.python.org/2/library/inspect.html#inspect.currentframe), так что она тоже может дать сбой ...
К каким конкретным случаям относится "файл терпит неудачу, если скрипт вызывается по-разному в Windows"?
требует ли этот ответ обновления для Python 3.4?
Что нужно иметь в виду при использовании модуля inspect для тех, кто может отключить сборщик мусора в своих скриптах: примечание о ссылочных циклах.
Люблю решение, но не pylint. Кто-нибудь знает хороший способ заставить Пилинт заткнуться?
Это ужасный совет с момента введения относительного импорта, который был задолго до того, как был написан этот ответ.
Эта статья объясняет это лучше. realpython.com/absolute-vs-relative-python-imports - имейте в виду, что окончательный ответ может зависеть от диапазона версий Python, на которые вы ориентируетесь.
Это заставило мой pytest сработать. Новая проблема: теперь mypy жалуется на несовместимый тип getfile "Optional [FrameType]"; ожидается "Union [Module, Type [Any], MethodType, FunctionType, TracebackType, FrameType, CodeType, Callable [..., Any]]"
from .dirBar import Bar
вместо:
from dirBar import Bar
на всякий случай может быть установлен другой dirBar и запутать читателя foo.py.
Я не смог сделать это в Windows. Это в Linux?
Он будет работать из скрипта, импортирующего Foo. то есть: main.py импортирует dirFoo.Foo. Если вы пытаетесь запустить Foo.py как скрипт, это не удастся. См. stackoverflow.com/questions/72852/…
Назовите меня слишком осторожным, но я предпочитаю делать свой более переносимым, потому что небезопасно предполагать, что файлы всегда будут в одном и том же месте на каждом компьютере. Лично у меня код сначала ищет путь к файлу. Я использую 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!")
Это, конечно, если вы не планируете упаковывать их вместе. Но в таком случае вам все равно не нужны два отдельных файла.
Файлы всегда будут находиться в одном и том же месте на всех компьютерах с указанием относительного пути.
Вот способ импортировать файл с одного уровня выше, используя относительный путь.
По сути, просто переместите рабочий каталог на уровень выше (или в любое относительное место), добавьте его в свой путь, а затем переместите рабочий каталог обратно туда, где он был запущен.
#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path = os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
Я не понимаю здесь логики. это слишком сложно
Если вы просто возитесь и не заботитесь о проблемах развертывания, вы можете использовать символическую ссылку (при условии, что ваша файловая система поддерживает ее), чтобы сделать модуль или пакет непосредственно видимым в папке запрашивающего модуля.
ln -s (path)/module_name.py
или же
ln -s (path)/package_name
Примечание. «Модуль» - это любой файл с расширением .py, а «пакет» - это любая папка, содержащая файл __init__.py (который может быть пустым). С точки зрения использования модули и пакеты идентичны - оба предоставляют содержащиеся в них «определения и операторы» по запросу с помощью команды import.
Самый простой способ без каких-либо изменений в вашем скрипте - установить переменную среды 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']
Пример относительного 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
На основании ответа это.
В этом случае, чтобы импортировать 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.
Ну, как вы упомянули, обычно вы хотите иметь доступ к папке с вашими модулями относительно того места, где запускается ваш основной скрипт, поэтому вы просто импортируете их.
Решение:
У меня есть сценарий в 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, чтобы убедиться, что все в порядке. Этот способ всегда работает, потому что согласно определению Python, sys.path, инициализируемый при запуске программы, первый элемент этого списка, path[0], является каталогом, содержащим сценарий, который использовался для вызова интерпретатора Python.
Если каталог сценария недоступен (например, если интерпретатор вызывается в интерактивном режиме или если сценарий читается со стандартного ввода), path[0] - это пустая строка, которая направляет Python на поиск модулей в текущем каталоге в первую очередь. Обратите внимание, что каталог сценария вставлен перед записями, вставленными в результате PYTHONPATH.
В моей первой простой программе на Python break_time.py: https://github.com/ltfschoen/PythonTest мне пришлось использовать одну косую черту вместо двух (например, site.addsitedir(sys.path[0]+'/includes')). Использую систему: MacOS v10.11.5, Python 2.7.12, IDLE IDE 2.7.12, Tk 8.5.9
Другое решение - установить пакет Py-require, а затем использовать следующее в Foo.py
import require
Bar = require('./dirBar/Bar')
На самом деле URL-адрес выглядит как pypi.org/project/require.py, и обратите внимание, что его необходимо установить через Pip.
@FlashSheridan Нет, это другой проект. Я удалил py-require, так как был уверен, что его никто не использует, хотя я не думал об этом посте. Если вам все еще нужна функция require(), вы можете взглянуть на мой проект Node.py: github.com/nodepy/nodepy
Я не разбираюсь в питоне, поэтому, если в моих словах что-то не так, просто скажите мне. Если ваша файловая иерархия устроена следующим образом:
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, поэтому он должен импортировать из более высокой иерархии.
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
Я думаю, что это совпадает с принципом организации иерархии файлов проекта, вы должны расположить модули с разными функциями в разных папках и просто оставить главного вызывающего снаружи, и вы можете импортировать все, что захотите.
Просто вы можете использовать: from Desktop.filename import something
Пример:
given that the file is name
test.pyin directoryUsers/user/Desktop, and will import everthing.
код:
from Desktop.test import *
Но убедитесь, что вы создали в этом каталоге пустой файл с именем "__init__.py".
не рекомендуется импортировать помеченные звездочкой. см .: stackoverflow.com/questions/2386714/why-is-import-bad
Я знаю, что именно поэтому я сначала написал import something, а затем сказал, чтобы упростить *, в основном, он не подходит для оперативной памяти, а также, если две функции имеют одно и то же имя, он накапливает ваш код
Это тоже работает, и это намного проще, чем что-либо с модулем sys:
with open("C:/yourpath/foobar.py") as f:
eval(f.read())
Если OP собирался жестко запрограммировать путь, они все равно могли бы просто вставить этот путь в PYTHONPATH. Я думаю, что дело в том, что путь не жестко закодирован, так как он может сломаться где-нибудь еще.
Может быть, похоже на stackoverflow.com/questions/72852/…?