Скрипты Python в отдельной директории: структура и выполнение

Раздел: Python -> Создание и выполнение скриптов

Основные подходы к работе со скриптами в папке Python

Наиболее эффективное решение - создание четкой структуры проекта, где все скрипты организованы в пакеты с обязательным файлом __init__.py. Такой подход позволяет легко импортировать модули, избегать путаницы с путями и запускать скрипты из корневой директории.

Пример минимальной структуры:


my_project/
├── main.py
├── utils/
│   ├── __init__.py
│   └── helpers.py
└── data/
    └── __init__.py

как запустить скрипт python в windows (выполнение скриптов python)

Файл main.py может импортировать модуль helpers следующим образом:


from utils.helpers import some_function

some_function()

Python готовый скрипт (примеры скриптов python)

Запуск осуществляется командой python main.py из папки my_project. Все импорты работают корректно, так как корень проекта автоматически попадает в sys.path.

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

Типичная ошибка:

Забыть создать __init__.py в подпапке - тогда импорт выдаст ModuleNotFoundError.

Решение: добавить пустой файл __init__.py в каждую папку, которая должна быть пакетом.

Как сделать, чтобы скрипты из любой папки импортировались без изменения структуры?

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


import sys
sys.path.append('/home/user/my_scripts')

import custom_module

Python папка скрипта (работа со скриптами python)

Проблема: путь может быть жёстко задан, что снижает переносимость. Альтернатива - использовать относительный путь os.path.abspath('..').

Ошибка:

ModuleNotFoundError после добавления пути из-за опечатки или неверного разделителя. Решение: использовать os.path.normpath() или pathlib.Path.

Как импортировать модули из соседней папки без изменения sys.path?

При работе с пакетами (наличие __init__.py) можно использовать относительные импорты с точкой:


# внутри pkg/subpkg/module.py
from .. import parent_module

Python 3 скрипты (создание скриптов на python)

Такой импорт работает только внутри пакета, когда скрипт запускается как модуль (python -m pkg.subpkg.module).

Проблема:

ImportError: attempted relative import with no known parent package - возникает при попытке запуска скрипта напрямую (python module.py). Решение: запускать через -m или использовать абсолютные импорты с добавлением корня в sys.path.

Как запустить скрипт, находящийся в другой папке, не перемещая его?

Можно указать полный или относительный путь к скрипту при запуске:


python /path/to/project/scripts/process.py

Однако при этом sys.path[0] станет /path/to/project/scripts, а не корень проекта. Это часто ломает импорты. Лучше использовать python -m с точкой вместо пути:


python -m scripts.process

Для этого корень проекта должен быть доступен в PYTHONPATH или находиться в текущей директории.

Ошибка:

ModuleNotFoundError при попытке импортировать модули из проекта. Решение: задать переменную окружения PYTHONPATH или запускать скрипт из корня.

Как сделать один скрипт и исполняемым, и импортируемым модулем?

Использовать конструкцию if __name__ == '__main__':


def main():
    # логика скрипта
    pass

if __name__ == '__main__':
    main()

При импорте из другого скрипта блок if не выполняется, а функция main остаётся доступной. Цель: переиспользование кода без побочных эффектов.

Распространённая проблема:

Весь код написан на верхнем уровне - при импорте он сразу выполняется. Решение: обернуть исполняемую часть в функцию и вызвать её только в блоке if __name__.

Расширенные примеры работы со скриптами в папке Python

Пример 1: Многоуровневая структура с взаимными импортами

Рассмотрим проект:

Пример

project/
├── main.py
├── lib/
│   ├── __init__.py
│   ├── calc.py
│   └── io.py
└── config.py

Содержимое calc.py:

Пример

def add(a, b):
    return a + b

io.py импортирует calc и config:

Пример

from lib.calc import add
from config import DEBUG

def process(data):
    if DEBUG:
        print("Processing...")
    return add(data, 10)

main.py:

Пример

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))

from lib.io import process
from config import VERSION

def main():
    print(f"Version {VERSION}")
    result = process(5)
    print(f"Result: {result}")

if __name__ == '__main__':
    main()

Результат запуска python main.py:

Version 1.0
Processing...
Result: 15

Пояснение: добавление корня проекта в sys.path через Path(__file__).parent гарантирует корректные импорты независимо от того, откуда запущен скрипт.

Пример 2: Использование PYTHONPATH для постоянной настройки

Переменная окружения PYTHONPATH содержит пути, которые Python добавляет в sys.path при старте. Установка в Linux/macOS:

Пример

export PYTHONPATH="/home/user/my_project:$PYTHONPATH"

После этого можно запускать любой скрипт внутри my_project с импортами, не думая о путях:

$ python scripts/process.py   # работает, если scripts/process.py использует from lib import ...

Windows (CMD):

Пример

set PYTHONPATH=C:\Users\user\my_project;%PYTHONPATH%

Рекомендуется добавлять эту команду в профиль оболочки или использовать IDE (например, PyCharm автоматически добавляет корень проекта).

Пример 3: Динамическое добавление путей с помощью sys.path.insert

Когда структура папок заранее неизвестна, можно вычислить путь относительно самого скрипта:

Пример

import sys
from pathlib import Path

# корень проекта - на два уровня выше текущего файла
project_root = Path(__file__).resolve().parent.parent
if str(project_root) not in sys.path:
    sys.path.insert(0, str(project_root))

# теперь импорты работают
from tools.parsers import parse_file

Такой подход позволяет использовать один и тот же скрипт из разных мест, если он знает своё местоположение.

Пример 4: Запуск скрипта как модуля с аргументами командной строки

Скрипт scripts/process.py:

Пример

import sys, argparse

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', required=True)
    return parser.parse_args()

if __name__ == '__main__':
    args = parse_args()
    print(f"Input file: {args.input}")

Запуск из корня проекта:

Пример

python -m scripts.process --input data/sample.txt

Результат:

Input file: data/sample.txt

Пояснение: ключ -m делает скрипт частью пакета, поэтому импорты внутри него видят корень проекта (если он добавлен в PYTHONPATH или текущая папка - корень).

Пример 5: Обработка ошибок при импорте из папки скрипта

Если скрипт должен работать и как модуль, и как самостоятельный файл, можно использовать блок try-except с разными способами импорта:

Пример

try:
    # при запуске как модуль (python -m mypackage.script)
    from . import config
except ImportError:
    # при запуске напрямую (python script.py)
    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).parent))
    import config

config.load()

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

Работа со скриптами Python - comments

En
Python папка скрипта (python)