Ответ 1
Правильный способ сделать это - использовать __init__.py
, setup.py
и setuptools
пакет Python:
myPackage/
myPackage/
__init__.py
setup.py
Эта ссылка имеет все этапы.
Я стараюсь, чтобы проект наукоемкой данных был хорошо организован, поэтому я создал каталог внутри моего каталога src
с именем utils
, который содержит файл с именем helpers.py
, который содержит некоторые вспомогательные функции, которые будут используется во многих сценариях. Какова наилучшая практика того, как я должен импортировать func_name
из src/utils/helpers.py
в файл в совершенно другом каталоге, например src/processing/clean_data.py
?
Я вижу ответы на этот вопрос, и я реализовал решение, которое работает, но это кажется уродливым:
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))
Я делаю это правильно? Нужно ли добавлять это к каждому script, который хочет импортировать func_name
, например train_model.py
?
Моя текущая структура папок проекта:
myproject
/notebooks
notebook.ipynb
/src
/processing
clean_data.py
/utils
helpers.py
/models
train_model.py
__init__.py
Примеры файлов:
# clean_data.py
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))
from src.utils.helpers import func_name
func_name()
# helpers.py
def func_name():
print('I'm a helper function.')
Правильный способ сделать это - использовать __init__.py
, setup.py
и setuptools
пакет Python:
myPackage/
myPackage/
__init__.py
setup.py
Эта ссылка имеет все этапы.
Прежде всего, позвольте мне рассказать о различиях между Python модулем и пакетом Python, чтобы обе мы были на одной странице. ✌
import aModuleName
# Here 'aModuleName' is just a regular .py file.
__init__.py
. ✔ from aPackageName import aModuleName
# Here 'aPackageName` is a folder with a `__init__.py` file
# and 'aModuleName', which is just a regular .py file.
Следовательно, когда у нас есть каталог проекта с именем proj-dir следующей структуры ⤵
proj-dir
--|--__init__.py
--package1
--|--__init__.py
--|--module1.py
--package2
--|--__init__.py
--|--module2.py
🔎 Обратите внимание, что я также добавил пустой
__init__.py
в proj-dir, который также делает его пакетом.
👍 Теперь, если вы хотите импортировать любой объект python из module2 из package2 в module1 из package1, то оператор import в файле module1.py будет
from package2.module2 import object2
# if you were to import the entire module2 then,
from package2 import module2
Прежде всего позвольте мне пояснить вам, что импортирование всего модуля, если вы собираетесь использовать его часть, тогда это не очень хорошая идея. Вместо этого вы можете использовать from
для импорта определенной функции в библиотеке/пакете. Делая это, вы делаете свою программу эффективной с точки зрения памяти и производительности.
Чтобы узнать больше, обратитесь к ним:
Net давайте рассмотрим решение.
Прежде чем приступать к решению, позвольте мне пояснить вам использование файла __init__.py
. Он просто сообщает интерпретатору python, что присутствующие там файлы *. Py импортируются, что означает, что они являются модулями и/являются частью пакета.
Итак, если у вас нет N подкаталогов, вы должны поместить файл __init__.py
во все эти вспомогательные каталоги, чтобы их можно было импортировать. Внутри файла __init__.py
вы также можете добавить дополнительную информацию, например, какой путь должен быть включен, функции по умолчанию, переменные, область видимости и т.д. Чтобы узнать об этом просто google о файле __init__.py
или взять некоторую библиотеку python и пройти через тот же файл __init__.py
, чтобы узнать об этом. (Здесь лежит решение)
Дополнительная информация:
Итак, как указано @Sushant Chaudhary, ваша структура проекта должна быть похожа на
proj-dir
--|--__init__.py
--package1
--|--__init__.py
--|--module1.py
--package2
--|--__init__.py
--|--module2.py
Итак, если я поместил файл
__init__.py
в мой каталог, как показано выше, Will он должен быть импортируемым и работать нормально?да и нет.
Если вы импортируете модули в этот каталог проекта/пакета.
например, в вашем случае
вы импортируете package1.module1 в pakage2.module2 как from package1 import module1
.
Здесь вам нужно импортировать базовый dir внутри вспомогательных модулей, Почему? проект будет работать нормально, если вы используете модуль из того же места. i.e: внутри package2 как python module2.py, Но будет бросать ModuleNotFoundError
Если вы запустите модуль из другого каталога. i.e: любой другой путь, кроме пакета package2, например, в proj-dir как python package1/module1.py
. Это то, что происходит в вашем случае. Вы используете модуль из project-dir.
Итак, как это исправить?
Вам нужно добавить путь к пути к системному пути в module1.py как
from sys import path
dir_path = "/absolute/path/to/proj-dir"
sys.path.insert(0, dir_path)
В proj-dir вы должны добавить все пути дополнительного модуля в файл __init__.py
.
Например:
#__init__.py under lxml
# this is a package
def get_include():
"""
Returns a list of header include paths (for lxml itself, libxml2
and libxslt) needed to compile C code against lxml if it was built
with statically linked libraries.
"""
import os
lxml_path = __path__[0]
include_path = os.path.join(lxml_path, 'includes')
includes = [include_path, lxml_path]
for name in os.listdir(include_path):
path = os.path.join(include_path, name)
if os.path.isdir(path):
includes.append(path)
return includes
Это __init__.py
файл lxml (библиотека python для анализа html, xml данных). Вы можете передать любой файл __init__.py
в любые библиотеки python с дополнительными модулями. ex (os, sys). Здесь я упомянул lxml, потому что думал, что вам будет легко понять. Вы даже можете проверить файл __init__.py
в других библиотеках/пакетах. У каждого будет свой собственный путь определения пути для подмодулей.
Если вы пытаетесь импортировать модули вне каталога. Затем вам нужно экспортировать путь к модулю, чтобы другие модули могли находить их в переменных среды. Это можно сделать, добавив абсолютный путь базового каталога в PYTHONPATH или PATH.
Узнать больше:
Итак, чтобы решить вашу проблему, укажите пути ко всем вспомогательным модулям в __init__.py
файле в proj-dir и добавьте /absolute/path/to/proj-dir либо до PYTHONPATH
, либо PATH
.
Надеюсь, что ответ объясняет вам использование __init__.py
и решает вашу проблему.
В Linux вы можете просто добавить путь к родительской папке вашего каталога src
в ~/.local/lib/python3.6/site-packages/my_modules.pth
. Видеть
Использование файлов .pth. Затем вы можете импортировать модули в src
из любой точки вашей системы.
NB1: Замените python3.6
любой версией Python, которую вы хотите использовать.
NB2: Если вы используете Python2.7 (не знаете для других версий), вам нужно будет создать файлы __init__.py
(empty) в src/
и src/utils
.
NB3: любое имя .pth
файла в порядке для my_modules.pth
.
Да, вы можете импортировать код только из установленных пакетов или из файлов в рабочий каталог или подкаталоги.
как я его вижу, ваша проблема будет решена, если у вас будет установлен ваш модуль или пакет, например, один пакет, который устанавливается, а затем импортирует (numpy, xml, json и т.д.).
У меня также есть пакет, который я постоянно использую во всех моих проектах, ulitilies, и я знаю, что это боль при импорте.
вот описание того, как упаковать приложение python, чтобы сделать его возможным: https://marthall.github.io/blog/how-to-package-a-python-app/
Перейдите в папку установки python
Перейдите в lib
Перейдите на сайт-пакеты
Создайте новый файл с именем any_thing_you_want.pth
Введите .../src/utils/helpers.py
внутри этого файла с помощью вашего любимого текстового редактора
Примечание: эллипсис до scr/utils/helpers.py
будет выглядеть примерно так: C:/Users/blahblahblah/python_folders/scr...
< - ВАМ НУЖНО ЭТОТ!
Это дешевый выход, но он делает код чистым и наименее сложным. Недостатком является то, что для каждой папки, в которой находятся ваши модули, example.pth понадобится. Upside: работает с Windows вплоть до Windows 10