Нужно ли добавлять каталог проекта в системный путь в каждом script для импорта функции из другого каталога?

Я стараюсь, чтобы проект наукоемкой данных был хорошо организован, поэтому я создал каталог внутри моего каталога 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.')

Ответ 1

Правильный способ сделать это - использовать __init__.py, setup.py и setuptools пакет Python:

myPackage/
    myPackage/
        __init__.py
    setup.py

Эта ссылка имеет все этапы.

Ответ 2

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


Модуль - один .py файл (или файлы), который импортируется под одним импортом и используется. ✔

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

Надеюсь, это простое объяснение объясняет ваши сомнения в механизме импорта Python и решает проблему. Если нет, то сделайте комментарий здесь. 😊

Ответ 3

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

Ответ 4

В 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.

Ответ 5

Да, вы можете импортировать код только из установленных пакетов или из файлов в рабочий каталог или подкаталоги.

Ответ 6

как я его вижу, ваша проблема будет решена, если у вас будет установлен ваш модуль или пакет, например, один пакет, который устанавливается, а затем импортирует (numpy, xml, json и т.д.).

У меня также есть пакет, который я постоянно использую во всех моих проектах, ulitilies, и я знаю, что это боль при импорте.

вот описание того, как упаковать приложение python, чтобы сделать его возможным: https://marthall.github.io/blog/how-to-package-a-python-app/

Ответ 7

  • Перейдите в папку установки 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