Импорт модуля из относительного пути



как импортировать модуль Python с учетом его относительного пути?



например, если dirFoo содержит Foo.py и dirBar и dirBar содержит Bar.py, как я могу импортировать Bar.py на Foo.py?



вот визуальное представление:



dirFoo
Foo.py
dirBar
Bar.py


Foo желает включить Bar, но реструктуризация иерархии папок не является вариантом.

621   23  

23 ответов:

предполагая, что оба ваших каталога являются реальными пакетами Python (есть __init__.py file 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 использовать ваш модуль вместо установленных в системе.

предупреждение! Я не знаю, что происходит, когда текущий модуль находится внутри . Это, вероятно, тоже не удается.

убедитесь, что у дирбара есть __init__.py file -- это делает каталог в пакет 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.путь инициализируется из этих мест:

  1. каталог, содержащий входной скрипт (или текущий справочник.)
  2. PYTHONPATH (список имен каталогов, с тем же синтаксис как путь переменной оболочки).
  3. установка зависит от значения по умолчанию.

просто запустите:

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 (который может быть пустой файл.) С точки зрения использования модули и пакеты идентичны - оба раскрывают содержащиеся в них "определения и операторы", как это требуется через .

см.:http://docs.python.org/2/tutorial/modules.html

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, так что вы убедитесь, что все идет нормально. Этот способ всегда работает, потому что по определению Python sys.path как инициализировать по запуск программы, Первый пункт этого списка,path[0], это каталог, содержащий сценарий, который был использован для вызова интерпретатора Python.

если каталог скриптов недоступен (например, если интерпретатор вызывается интерактивно или если скрипт считывается со стандартного ввода),path[0] это пустая строка, которая направляет Python для поиска модулей в текущем каталоге в первую очередь. Обратите внимание, что каталог сценария вставляется перед записями, вставленными в результате PYTHONPATH.

другим решением было бы установить py-require пакет, а затем использовать следующее в Foo.py

import 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.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 do что-то:

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

    Ничего не найдено.