Импорт файлов из другой папки - PullRequest
1044 голосов
/ 08 декабря 2010

У меня следующая структура папок.

application/app/folder/file.py

и я хочу импортировать некоторые функции из file.py в другой файл Python, который находится в

application/app2/some_folder/some_file.py

Я пробовал

from application.app.folder.file import func_name

и некоторые другие различные попытки, но до сих пор мне не удавалось правильно импортировать. Как я могу это сделать?

Ответы [ 21 ]

17 голосов
/ 01 октября 2018

Я столкнулся с той же проблемой, особенно при импорте нескольких файлов, так мне удалось ее преодолеть.

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name
15 голосов
/ 30 июля 2018

В Python 3.4 и новее вы можете импортировать напрямую из исходного файла (ссылка на документацию) . Это не самое простое решение, но я включаю этот ответ для полноты.

Вот пример. Сначала импортируемый файл с именем foo.py:

def announce():
    print("Imported!")

Код, который импортирует файл выше, в значительной степени вдохновленный примером в документации:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

Выход:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Обратите внимание, что имя переменной, имя модуля и имя файла не обязательно должны совпадать. Этот код все еще работает:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

Выход:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Программный импорт модулей был представлен в Python 3.1 и дает вам больше контроля над тем, как импортируются модули. Обратитесь к документации для получения дополнительной информации.

13 голосов
/ 17 декабря 2017

Попробуйте относительный импорт Python:

from ...app.folder.file import func_name

Каждая начальная точка - это еще один более высокий уровень в иерархии, начиная с текущего каталога.


Проблемы?Если это не работает для вас, то вы, вероятно, получаете немного от относительного импорта многих приобретенных товаров.Прочитайте ответы и комментарии для получения более подробной информации: Как исправить «Попытка относительного импорта в неупакованном виде» даже с __init __. Py

Подсказка: иметь __init__.py на каждом уровне каталога.Вам может понадобиться python -m application.app2.some_folder.some_file (не включая .py), который вы запускаете из каталога верхнего уровня или у вас есть этот каталог верхнего уровня в вашей PYTHONPATH. Уф!

12 голосов
/ 04 октября 2017

Использование sys.path.append с абсолютным путем не идеально при перемещении приложения в другие среды. Использование относительного пути не всегда работает, потому что текущий рабочий каталог зависит от того, как был вызван скрипт.

Поскольку структура папок приложения фиксирована, мы можем использовать os.path, чтобы получить полный путь к модулю, который мы хотим импортировать. Например, если это структура:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

И скажем, вы хотите импортировать модуль "манго". Вы можете сделать следующее в vanilla.py:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

Конечно, вам не нужна переменная mango_dir.

Чтобы понять, как это работает, посмотрите на этот пример интерактивного сеанса:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

И проверьте документацию os.path .

12 голосов
/ 27 марта 2016

Это работает для меня на Windows

# some_file.py on mainApp/app2 
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file
9 голосов
/ 18 марта 2017

Я совершенно особенный: я использую Python с Windows!

Я просто дополняю информацию: и для Windows, и для Linux как относительный, так и абсолютный путь в sys.path (мне нужны относительные пути, потому что я используюмои скрипты на нескольких ПК и в разных основных каталогах).

И при использовании Windows оба \ и / могут использоваться в качестве разделителя для имен файлов, и, конечно, вы должны удвоить \ в строки Python,
некоторые допустимые примеры:

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(примечание: я думаю, что / удобнее, чем \, событие, если оно менее "родное" для Windows, потому что оно совместимо с Linux и проще для записи и копирования в проводник Windows)

6 голосов
/ 23 декабря 2015

Если цель загрузки модуля по определенному пути - помочь вам при разработке пользовательского модуля, вы можете создать символическую ссылку в той же папке тестового скрипта, которая указывает на корень пользовательского модуля. Эта ссылка на модуль будет иметь приоритет над любыми другими модулями, установленными с таким же именем, для любого сценария, выполняемого в этой папке.

Я протестировал это в Linux, но оно должно работать в любой современной ОС, поддерживающей символические ссылки.

Одним из преимуществ этого подхода является то, что вы можете указывать на модуль, который находится в вашей собственной рабочей копии локальной ветки SVC, что может значительно упростить время цикла разработки и уменьшить режимы отказов при управлении различными версиями модуля. *

2 голосов
/ 30 ноября 2017

В моем случае у меня был класс для импорта. Мой файл выглядел так:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

В свой основной файл я включил код через:

path.append("/opt/path/to/code/")
from log_helper import LogHelper
1 голос
/ 13 июля 2017

Вы можете обновить оболочку Python, нажав клавишу f5, или перейдите в Run-> Run Module.Таким образом, вам не нужно менять каталог, чтобы что-то прочитать из файла.Python автоматически изменит каталог.Но если вы хотите работать с разными файлами из разных каталогов в оболочке Python, то вы можете изменить каталог в sys, , как ранее Кэмерон говорил

1 голос
/ 27 июля 2018

Поэтому я просто щелкнул правой кнопкой мыши на своей IDE и добавил новую folder, и мне стало интересно, почему я не смог импортировать ее. Позже я понял, что должен щелкнуть правой кнопкой мыши и создать пакет Python, а не классическую папку файловой системы. Или посмертный метод - добавление __init__.py (что заставляет python рассматривать папку файловой системы как пакет), как упоминалось в других ответах. Добавление этого ответа на случай, если кто-то пойдет по этому пути.

...