Импортировать модуль из относительного пути - PullRequest
731 голосов
/ 11 ноября 2008

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

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

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

dirFoo\
    Foo.py
    dirBar\
        Bar.py

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

Ответы [ 23 ]

325 голосов
/ 23 мая 2011

Предполагая, что обе ваши директории являются реальными пакетами 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. Это, вероятно, тоже не удается.

320 голосов
/ 11 ноября 2008

Убедитесь, что в dirBar есть файл __init__.py - это превращает каталог в пакет Python.

252 голосов
/ 11 ноября 2008

Вы также можете добавить подкаталог в путь к Python, чтобы он импортировался как обычный скрипт.

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
114 голосов
/ 26 ноября 2010
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule
97 голосов
/ 09 декабря 2010

Просто сделайте простые вещи, чтобы импортировать файл .py из другой папки.

Допустим, у вас есть каталог вроде:

lib/abc.py

Тогда просто сохраните пустой файл в папке lib с именем

__init__.py

А затем используйте

from lib.abc import <Your Module name>

Храните файл __init__.py в каждой папке иерархии модуля импорта.

78 голосов
/ 11 ноября 2008

Если вы структурируете свой проект следующим образом:

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 - это просто пустой файл.

44 голосов
/ 12 ноября 2008

Самый простой способ - использовать 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)
43 голосов
/ 11 ноября 2008

Это соответствующий PEP:

http://www.python.org/dev/peps/pep-0328/

В частности, предполагается, что каталог dirFoo является каталогом из каталога dirBar ...

В dirFoo \ Foo.py:

from ..dirBar import Bar
22 голосов
/ 11 февраля 2013

Самый простой способ без каких-либо изменений в вашем скрипте - установить переменную окружения PYTHONPATH. Поскольку sys.path инициализируется из следующих мест:

  1. Каталог, содержащий скрипт ввода (или текущий каталог).
  2. PYTHONPATH (список имен каталогов, с одинаковыми синтаксис в качестве переменной оболочки PATH).
  3. Зависит от установки по умолчанию.

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

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']
12 голосов
/ 15 сентября 2010

На мой взгляд, лучший выбор - поместить __ init __. Py в папку и вызвать файл с

from dirBar.Bar import *

Не рекомендуется использовать sys.path.append (), потому что что-то может пойти не так, если вы используете то же имя файла, что и в существующем пакете python. Я не проверял это, но это будет неоднозначно.

...