Импорт модулей из родительской папки
Я запускаю Python 2.5.
Это мое дерево папок:
ptdraft/
nib.py
simulations/
life/
life.py
(У меня также есть __init__.py
в каждой папке, опущен здесь для удобочитаемости)
Как импортировать модуль nib
из модуля life
? Я надеюсь, что можно обойтись без использования sys.path.
Примечание. Основной выполняемый модуль находится в папке ptdraft
.
Ответы
Ответ 1
Кажется, что проблема не связана с тем, что модуль находится в родительском каталоге или что-то в этом роде.
Вам нужно добавить каталог, содержащий ptdraft
в PYTHONPATH
Вы сказали, что import nib
работал с вами, что, вероятно, означает, что вы добавили ptdraft
(не его родительский) в PYTHONPATH.
Ответ 2
Вы можете использовать относительный импорт (python >= 2.5):
from ... import nib
(Что нового в Python 2.5) PEP 328: Абсолютный и относительный импорт
EDIT: добавлена другая точка. ' чтобы подняться на два пакета
Ответ 3
Относительный импорт (как в from.. import mymodule
) работает только в пакете. Чтобы импортировать "mymodule", который находится в родительском каталоге вашего текущего модуля:
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
import mymodule
изменить: атрибут __file__
не всегда дается. Вместо использования os.path.abspath(__file__)
я теперь предложил использовать модуль inspect для получения имени файла (и пути) текущего файла.
Ответ 4
Я отправил аналогичный ответ также на вопрос об импорте из родственных пакетов. Вы можете увидеть это здесь. Следующее тестируется на Python 3.6.5, (Anaconda, conda 4.5.1), машина с Windows 10.
Решение без взлома sys.path
Настроить
Я предполагаю ту же структуру папок, что и в вопросе
.
└── ptdraft
├── __init__.py
├── nib.py
└── simulations
├── __init__.py
└── life
├── __init__.py
└── life.py
Я звоню .
корневая папка, и в моем случае она находится в C:\tmp\test_imports
.
меры
1) Добавьте файл setup.py в корневую папку
Содержимое setup.py
может быть просто
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
В принципе "любой" setup.py будет работать. Это просто минимальный рабочий пример.
2) Используйте виртуальную среду
Если вы знакомы с виртуальными средами, активируйте одну и перейдите к следующему шагу. Использование виртуальных сред не является абсолютно обязательным, но они действительно помогут вам в долгосрочной перспективе (когда у вас более 1 проекта..). Самые основные шаги (запустить в корневой папке)
- Создать виртуальную среду
- Активировать виртуальную среду
-
./venv/bin/activate
./venv/bin/activate
(Linux) или ./venv/Scripts/activate
(Win)
Чтобы узнать больше об этом, просто посмотрите в Google "Python Virtual Env Tutorial" или подобное. Вам, вероятно, никогда не понадобятся какие-либо другие команды, кроме создания, активации и деактивации.
После того, как вы создали и активировали виртуальную среду, ваша консоль должна дать имя виртуальной среды в скобках.
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
3) pip установите ваш проект в редактируемое состояние
Установите пакет верхнего уровня myproject
с помощью pip
. Хитрость заключается в использовании флага -e
при установке. Таким образом, он устанавливается в редактируемом состоянии, и все изменения, внесенные в файлы .py, будут автоматически включены в установленный пакет.
В корневом каталоге запустите
pip install -e.
(обратите внимание на точку, это означает "текущий каталог")
Вы также можете увидеть, что он установлен с помощью pip freeze
(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
4) Импорт путем добавления mainfolder
к каждому импорту
В этом примере mainfolder
будет ptdraft
. Преимущество этого заключается в том, что вы не столкнетесь с конфликтами имен с другими именами модулей (из стандартной библиотеки Python или сторонних модулей).
Пример использования
nib.py
def function_from_nib():
print('I am the return value from function_from_nib!')
life.py
from ptdraft.nib import function_from_nib
if __name__ == '__main__':
function_from_nib()
Запуск life.py
(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!
Ответ 5
Если добавление папки вашего модуля в PYTHONPATH не сработало, вы можете изменить список sys.path в своей программе, где интерпретатор Python ищет модули для импорта, документация python говорит:
Когда импортируется модуль с именем спам, интерпретатор сначала ищет встроенный модуль с этим именем. Если он не найден, он ищет файл с именем spam.py в списке каталогов, заданных переменной sys.path. sys.path инициализируется из этих местоположений:
-
- каталог, содержащий вход script (или текущий каталог).
- PYTHONPATH (список имен каталогов с тем же синтаксисом, что и переменная оболочки PATH).
- зависит от установки по умолчанию.
После инициализации программы Python могут изменять sys.path. Каталог, содержащий выполняемый script, помещается в начало пути поиска, опережая путь стандартной библиотеки. Это означает, что скрипты в этом каталоге будут загружены вместо модулей с тем же именем в каталоге библиотеки. Это ошибка, если не требуется замена.
Зная это, вы можете сделать следующее в своей программе:
import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')
# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft
Ответ 6
Вы можете использовать зависящий от ОС путь в "пути поиска модуля", который указан в sys.path.
Таким образом, вы можете легко добавить родительский каталог, например, следующий
import sys
sys.path.insert(0,'..')
Если вы хотите добавить родительский родительский каталог,
sys.path.insert(0,'../..')
Ответ 7
Не знаю много о python 2.
В python 3 родительскую папку можно добавить следующим образом:
import sys
sys.path.append('..')
... и затем можно импортировать модули из него
Ответ 8
Вот простой ответ, чтобы вы могли увидеть, как он работает, маленький и кроссплатформенный.
Он использует только встроенные модули (os
, sys
и inspect
), поэтому должен работать
в любой операционной системе (ОС), потому что Python предназначен для этого.
Более короткий код для ответа - меньше строк и переменных
from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module # Replace "my_module" here with the module name.
sys.path.pop(0)
Для меньшего количества строк, чем это, замените вторую строку import os.path as path, sys, inspect
,
добавить inspect.
в начале getsourcefile
(строка 3) и удалите первую строку.
- однако это импортирует весь модуль, поэтому может потребоваться больше времени, памяти и ресурсов.
Код для моего ответа (более длинная версия)
from inspect import getsourcefile
import os.path
import sys
current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]
sys.path.insert(0, parent_dir)
import my_module # Replace "my_module" here with the module name.
Он использует пример из ответа Как получить путь текущего
исполняемый файл в Python? найти источник (имя файла) работающего кода с помощью встроенного инструмента.
from inspect import getsourcefile
from os.path import abspath
Далее, где бы вы ни хотели найти исходный файл, просто используйте:
abspath(getsourcefile(lambda:0))
Мой код добавляет путь к sys.path
, список путей Python
потому что это позволяет Python импортировать модули из этой папки.
После импорта модуля в коде рекомендуется запустить sys.path.pop(0)
в новой строке.
когда в этой добавленной папке есть модуль с тем же именем, что и другой импортируемый модуль
позже в программе. Вам нужно удалить элемент списка, добавленный до импорта, а не другие пути.
Если ваша программа не импортирует другие модули, безопасно не удалять путь к файлу, потому что
после завершения программы (или перезапуска оболочки Python) любые изменения, внесенные в sys.path
исчезают.
Примечания о переменной имени файла
Мой ответ не использует переменную __file__
чтобы получить путь к файлу/имя файла
код, потому что пользователи здесь часто называют его ненадежным. Вы не должны использовать это
для импорта модулей из родительской папки в программы, используемые другими людьми.
Некоторые примеры, где это не работает (цитата из этого вопроса):
• его нельзя найти на некоторых платформах • иногда это не полный путь к файлу
-
py2exe
не имеет атрибута __file__
, но есть обходной путь - При запуске из IDLE с
execute()
атрибут __file__
отсутствует - OS X 10.6, где я получаю
NameError: global name '__file__' is not defined
Ответ 9
Вот более общее решение, которое включает родительский каталог в sys.path(работает для меня):
import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
Ответ 10
Я обнаружил, что следующий способ работает для импорта пакета из родительского каталога скрипта. В этом примере я хотел бы импортировать функции в env.py
из пакета app.db
.
└── my_application
└── alembic
└── env.py
└── app
├── __init__.py
└── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
Ответ 11
Для меня самый короткий и мой любимый oneliner для доступа к родительскому каталогу:
sys.path.append(os.path.dirname(os.getcwd()))
или же:
sys.path.insert(1, os.path.dirname(os.getcwd()))
os.getcwd() возвращает имя текущего рабочего каталога, os.path.dirname(directory_name) возвращает имя каталога для переданного.
На самом деле, по моему мнению, архитектура проекта Python должна выполняться так, чтобы ни один модуль из дочернего каталога не использовал ни один модуль из родительского каталога. Если что-то подобное происходит, стоит задуматься о дереве проекта.
Другой способ - добавить родительский каталог в системную переменную среды PYTHONPATH.
Ответ 12
import sys
sys.path.append('../')
Ответ 13
Если вы не находитесь в среде пакета с файлами __init__.py
, библиотека pathlib (входит в состав >= Python 3.4) делает очень кратким и интуитивно понятным добавление пути родительского каталога к PYTHONPATH:
import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))
Ответ 14
Вышеупомянутые решения тоже подойдут. Другое решение этой проблемы
Если вы хотите импортировать что-либо из каталога верхнего уровня. Затем,
from ...module_name import *
Также, если вы хотите импортировать какой-либо модуль из родительского каталога. Затем,
from ..module_name import *
Также, если вы хотите импортировать какой-либо модуль из родительского каталога. Затем,
from ...module_name.another_module import *
Таким образом, вы можете импортировать любой конкретный метод, если хотите.
Ответ 15
тот же стиль, что и в прошлом, но в меньшем количестве строк: P
import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)
Файл возвращает местоположение, в котором вы работаете в
Ответ 16
Работа с библиотеками.
Создайте библиотеку под названием nib, установите ее с помощью setup.py, пусть она будет находиться в пакетах сайтов, и ваши проблемы будут решены.
Вам не нужно заполнять все, что вы делаете, в одном пакете. Разбивайте его на части.
Ответ 17
В системе Linux вы можете создать мягкую ссылку из папки "life" в файл nib.py. Затем вы можете просто импортировать его, как:
import nib
Ответ 18
Вы также можете сделать символическую ссылку на путь модуля, который хотите импортировать, а затем использовать символическую ссылку для импорта. Создайте символическую ссылку в dist-пакетах python.
Чтобы создать символическую ссылку:
ln -s "/path/to/ptdraft" "/path/to/python/dist/packages/module_symlink_name"
Чтобы импортировать модуль в script:
from module_symlink_name import nib
Не нужно экспортировать путь python или перебирать путь sys.
Ответ 19
Простое решение для абсолютного пути в Windows 10:
import sys
sys.path.insert(0,'C:\\Users\\user01\\Desktop\\pipeline')
from folder1.folder2.filename import function_name
это импортирует функцию "имя_функции"
из: C:\Users\user01\Desktop\pipeline\folder1\folder2\filename
Ответ 20
вы можете добавить путь к каталогу в sys
import sys
import os
sys.path.append(os.path.__file__)