Аргументы запуска Python-скрипта при работе с файлами

Раздел: Работа с файлами -> Файловый ввод-вывод

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

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

Каким образом можно гибко и надёжно разобрать аргументы командной строки с поддержкой флагов, типов и справки?

Основное решение: модуль argparse. Он предоставляет декларативный способ описания ожидаемых аргументов, автоматически генерирует справку и проверяет типы.

import argparse

parser = argparse.ArgumentParser(description='Чтение содержимого файла')
parser.add_argument('filename', help='Имя файла для чтения')
parser.add_argument('--encoding', default='utf-8', help='Кодировка файла')
args = parser.parse_args()

with open(args.filename, 'r', encoding=args.encoding) as f:
    print(f.read())

ввод программ на python (ввод данных в программе python)

Пояснение: add_argument определяет позиционный аргумент filename и опциональный флаг --encoding. После вызова parse_args() значения доступны как атрибуты объекта args. При запуске без аргументов или с флагом -h выводится справка.

Типичная ошибка: забыть указать обязательный аргумент. argparse сам выдаст сообщение об ошибке. Если требуется обработать ошибку по-своему, можно использовать parser.parse_known_args().

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

Используется sys.argv - список строк, переданных в командной строке. Первый элемент - имя скрипта.

import sys

if len(sys.argv) < 2:
    print('Использование: python script.py filename')
    sys.exit(1)

filename = sys.argv[1]
try:
    with open(filename, 'r') as f:
        print(f.read())
except FileNotFoundError:
    print(f'Файл {filename} не найден')

Python file io (ввод-вывод файлов в python)

Пояснение: вручную проверяется количество аргументов. Для более сложной логики (флаги, значения по умолчанию) это быстро становится громоздким.

Проблемы: отсутствие автоматической проверки типов, необходимость ручного разбора флагов, уязвимость к пробелам в путях (если не использовать кавычки в командной строке).

Каким способом можно поддерживать как короткие, так и длинные имена опций (например, -o file и --output file)?

Модуль getopt из стандартной библиотеки позволяет разбирать аргументы в стиле C. Он менее удобен, чем argparse, но иногда используется для совместимости.

import sys
import getopt

try:
    opts, args = getopt.getopt(sys.argv[1:], 'ho:', ['help', 'output='])
except getopt.GetoptError as err:
    print(err)
    sys.exit(2)

output_file = None
for opt, arg in opts:
    if opt in ('-h', '--help'):
        print('Использование: ...')
        sys.exit()
    elif opt in ('-o', '--output'):
        output_file = arg

if args:
    input_file = args[0]
else:
    print('Требуется входной файл')
    sys.exit(1)

print(f'Вход: {input_file}, выход: {output_file}')

Python temp files (временные файлы в python)

Пояснение: getopt возвращает кортеж из опций и остальных аргументов. Строка 'ho:' означает: короткие опции h (без значения) и o: (с значением). Длинные аналоги указываются списком.

Типичная ошибка: забыть двоеточие после короткой опции, ожидающей значение. В результате значение не привяжется к опции. Также getopt не проверяет типы значений и не генерирует справку автоматически.

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

Можно обработать sys.argv вручную, например, с помощью цикла и условных операторов. Этот подход подходит для скриптов с одним-двумя параметрами.

import sys

args = sys.argv[1:]
filename = None
mode = 'r'

i = 0
while i < len(args):
    if args[i] == '-m' and i+1 < len(args):
        mode = args[i+1]
        i += 2
    elif args[i].startswith('-'):
        print(f'Неизвестная опция {args[i]}')
        sys.exit(1)
    else:
        filename = args[i]
        i += 1

if filename is None:
    print('Не указан файл')
    sys.exit(1)

print(f'Режим: {mode}, файл: {filename}')

Пояснение: вручную перебираются аргументы, распознаются флаги. Недостаток: код становится запутанным при росте числа опций.

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

- Python file utf 8 (кодировка utf-8 для файлов в python)
- Python config files (конфигурационные файлы в python)
- Python copy file (копирование файла в python)

Расширенные примеры работы с аргументами командной строки

Пример 1: argparse с проверкой существования файла

Пример
import argparse
import os

def file_exists(path):
    if not os.path.isfile(path):
        raise argparse.ArgumentTypeError(f'Файл {path} не существует')
    return path

parser = argparse.ArgumentParser(description='Подсчёт строк в файле')
parser.add_argument('file', type=file_exists, help='Путь к файлу')
parser.add_argument('--lines-start', type=int, default=1, help='Номер первой строки')
args = parser.parse_args()

with open(args.file, 'r') as f:
    lines = f.readlines()
print(f'Всего строк: {len(lines)}, начиная с {args.lines_start}')
$ python script.py nonexistent.txt
usage: script.py [-h] [--lines-start LINES_START] file
script.py: error: argument file: Файл nonexistent.txt не существует

$ python script.py existing.txt
Всего строк: 42, начиная с 1

Пример 2: Обработка нескольких файлов с помощью sys.argv и glob

Пример
import sys
import glob

if len(sys.argv) < 2:
    print('Укажите хотя бы один файл или шаблон (например, *.txt)')
    sys.exit(1)

files = []
for pattern in sys.argv[1:]:
    matched = glob.glob(pattern)
    if not matched:
        print(f'Предупреждение: нет файлов, соответствующих {pattern}')
    files.extend(matched)

print('Обрабатываются файлы:')
for f in files:
    with open(f, 'r') as fh:
        print(f'  {f}: {len(fh.readlines())} строк')
$ python script.py data/*.csv report.log
Обрабатываются файлы:
  data/a.csv: 100 строк
  data/b.csv: 200 строк
  report.log: 50 строк

Пример 3: argparse с подкомандами (subparsers) для разных операций с файлами

Пример
import argparse

def read_file(args):
    with open(args.file, 'r') as f:
        print(f.read())

def write_file(args):
    with open(args.file, 'w') as f:
        f.write(args.content or '')

parser = argparse.ArgumentParser(description='Файловый менеджер')
subparsers = parser.add_subparsers(dest='command')

read_parser = subparsers.add_parser('read', help='Чтение файла')
read_parser.add_argument('file')
read_parser.set_defaults(func=read_file)

write_parser = subparsers.add_parser('write', help='Запись в файл')
write_parser.add_argument('file')
write_parser.add_argument('--content', help='Текст для записи')
write_parser.set_defaults(func=write_file)

args = parser.parse_args()
if hasattr(args, 'func'):
    args.func(args)
else:
    parser.print_help()
$ python file_manager.py read example.txt
(содержимое файла)

$ python file_manager.py write new.txt --content 'Hello'
(создаёт файл с текстом)

Пример 4: Использование модуля fileinput для обработки файлов, переданных как аргументы

Пример
import fileinput
import sys

# Если файлы не указаны, читает stdin
for line in fileinput.input():
    if fileinput.isfirstline():
        print(f'--- {fileinput.filename()} ---')
    sys.stdout.write(line)
$ python script.py file1.txt file2.txt
--- file1.txt ---
(содержимое file1.txt)
--- file2.txt ---
(содержимое file2.txt)

Пример 5: getopt с длинными опциями и проверкой целочисленных значений

Пример
import sys
import getopt

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'n:c:', ['number=', 'count='])
    except getopt.GetoptError as err:
        print(str(err))
        sys.exit(1)

    number = None
    count = None
    for opt, val in opts:
        if opt in ('-n', '--number'):
            try:
                number = int(val)
            except ValueError:
                print('Опция --number требует целое число')
                sys.exit(1)
        elif opt in ('-c', '--count'):
            count = int(val)

    if args:
        files = args
    else:
        print('Укажите хотя бы один файл')
        sys.exit(1)

    print(f'Число: {number}, количество: {count}, файлы: {files}')

if __name__ == '__main__':
    main()
$ python script.py --number abc file.txt
Опция --number требует целое число

Аргументы командной строки файла Python - comments

En
Python file arguments (python)