Написание сценариев#

Язык Python часто называется языком написания сценариев.

Сценарий — это отдельные последовательности действий для автоматического выполнения задачи, то есть для автоматизации.

Автоматизация в широком смысле подразумевает под собой применение технических средств, экономико-математических методов и систем управления, освобождающих человека частично или полностью от непосредственного участия в процессах получения, преобразования, передачи и использования энергии, материалов или информации. Проще говоря, автоматизация нужна для исключения человеческого фактора и минимизации выполнения человеком рутинных задач. Примером рутинных задач могут служить: оформление технического отчёта (домашнего задания, расчётно-пояснительной записки по курсовой работе и т.д.), в котором меняются только числовые данные, графики, но не основной текст; проведение численных расчётов, экспериментов и др.

Язык Python очень прост в сравнении с другими распространёнными языками программирования. Он обладает простым и лаконичным синтаксисом, развитой стандартной библиотекой (то есть тем, что доступно “из коробки”) и богатым множеством сторонних библиотек ( SciPy, NumPy, Matplotlib, Pandas, NetworkX и многие другие ).

Несмотря на то, что Python изначально являлся языком создания сценариев, в настоящее время Python 3 является полноценным языком программирования, с помощью которого можно написать фактически любую программу (кроме ядра операционной системы).

Мы начнём знакомство с Python с простого — с написания несложных скриптов.

Простейший сценарий#

Простейшей программой, с которой начинается чуть ли не каждый учебник по любому языку программирования, является вывод на экран приветственной фразы “Hello, world!”. В Python это делается одной строкой:

print("Hello, world!")
Hello, world!

Только и всего!

Что содержит в себе этот код:

  • print — имя функции из стандартной библиотеки Python, обеспечивающей вывод данных в поток вывода. В данном случае вывод осуществляется в консоль.

  • print(...) — это вызов функции print. Круглые скобки в этом случае являются оператором вызова.

  • “Hello, world!” — это строковый литерал. Литерал — это, простыми словами, что-либо встроенное в код.

Запуск скриптов посредством командной строки#

Как правило, код пишется в специализированном редакторе наподобие VS Code, PyCharm и др. Поэтому для запуска рассмотренной программы вам нужно:

  1. Создать новую директорию. Например, так:

    $ mkdir hello
    
  2. Перейти в эту директорию:

    $ cd hello
    
  3. Открыть IDE или редактор кода в этой директории. VS Code, к примеру, в текущей директории можно открыть так:

    $ code .
    
  4. Создать Python-файл (.py), назвав его, к примеру, hello.py. Сделать это можно как в открывшемся редакторе, так и в терминале:

    $ touch hello.py
    
  5. Написать код в созданном файле hello/hello.py:

    print("Hello, world!")
    
  6. Запустить программу либо средствами IDE, либо через терминал:

    $ python hello.py
    

    Note

    В ряде дистрибутивов GNU/Linux наряду с современным интерпретатором Python 3 может быть установлен интерпретатор Python 2 (старая версия языка). Поэтому вместо python в терминале может потребоваться указывать python3.

В результате вы должны увидеть заветное приветствие.

Рассмотрим более осмысленный скрипт, автоматизирующий поиск корней квадратного уравнения.

Скрипт для решения квадратного уравнения#

В качестве учебного примера автоматизируем нахождение корней квадратного уравнения

\[ a x^2 + b x + c = 0. \]

Программа на вход должна получать коэффициенты \(a\), \(b\) и \(c\), выдавая значения корней \(x_1\) и \(x_2\) при любом значении дискриминанта.

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

Important

Всегда, прежде чем приступать к программному решению поставленной задачи, следует описать задачу и методику её решения обычным человеческим языком и языком математики. И только после того, как вы убедились, что понимаете, что вы решаете, зачем и почему. То есть вы понимаете цель и поставленные задачи, что собой представляет решение (число, набор чисел, график зависимости чего-то от чего-либо и т.д.), а также сформировали алгоритм решения задачи. После этого вы сможете уверенно подойти к программной реализации.

Решение квадратного уравнения есть задача тривиальная для студентов. Тем не менее рассмотрим, как сказанное применить к такой простой задаче.

Формулировка задачи и алгоритма её решения#

Используя заданные значения коэффициентов \(a\), \(b\), \(c\), найти корни \(x_1\), \(x_2\) квадратного уравнения

\[ a x^2 + b x + c = 0 \]

при любом значении дискриминанта \(D = b^2 - 4 a c\), \(D \in \mathbb{R}\) и при условии \(a \neq 0\).

Задача сформулирована. Сформируем алгоритм её решения.

  1. Проверить \(a \neq 0\). Если \(a = 0\), то завершить программу, так как она не для решения линейного уравнения.

  2. Рассчитать дискриминант \(D = b^2 - 4 a c\).

  3. Определить число корней. При \(D > 0\) — два вещественных корня; при \(D = 0\) — один вещественный корень; при \(D < 0\) — два сопряжённых комплексных корня.

  4. Рассчитать значения корней:

    \[ x_{1, 2} = \frac{-b \pm \sqrt{D}}{2 a}. \]

    При этом, в зависимости от знака \(D\) в программе необходимо учесть отрицательное число под корнем, чтобы избежать её краха (возникновения исключения).

Теперь можно приступать к написанию скрипта.

Программная реализация#

При написании программ не пользуйтесь Jupyter Notebook. В нём достаточно сложно писать и поддерживать программы. Он заточен в основном для Data Science, где пишут небольшие скрипты для обработки данных. Для разработки программ рекомендуется использовать VS Code, PyCharm и другие редакторы кода и IDE (Integrated Development Environment — интегрированная среда разработки). Далее предполагается, что используете что-либо, но не Jupyter Notebook.

Создайте директорию проекта (программы). Её можно назвать, например, quadric_equation:

$ mkdir quadric_equation

Данная директория должна являться рабочей. Перейдите в неё

cd quadric_equation

и создайте файл скрипта Python:

$ touch solve_quadric_eq.py

Запустите редактор кода. Например, VS Code:

$ code .

Далее можете редактировать скрипт с помощью VS Code.

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

# Из пакета математики стандартной библиотеки
# возьмём функцию sqrt извлечения квадратного корня.
# Существует два пакета: math для математики с вещественными
# числами и cmath для операций с комплексными числами.
# Нам нужные обе.
from cmath import sqrt as csqrt # даём псевдоним, чтобы отличать от вещественного sqrt
from math import sqrt


# Задаём коэффициенты
a = 1
b = -13
c = 36

# Находим дискриминант
discriminant = b*b - 4*a*c

# Находим корни
if discriminant > 0:
    x1 = (-b - sqrt(discriminant)) / (2*a)
    x2 = (-b + sqrt(discriminant)) / (2*a)
elif discriminant == 0:
    x1 = -b / (2*a)
    x2 = x1
else:
    x1 = (-b - csqrt(complex(discriminant))) / (2*a)
    x2 = (-b + csqrt(complex(discriminant))) / (2*a)

# Показываем результат
print("x1 =", x1)
print("x2 =", x2)
x1 = 4.0
x2 = 9.0

Проверим два оставшихся случая (\(D = 0\) и \(D < 0\)):

# Задаём коэффициенты (D = 0)
a = 1
b = -4
c = 4

# Находим дискриминант
discriminant = b*b - 4*a*c

# Находим корни
if discriminant > 0:
    x1 = (-b - sqrt(discriminant)) / (2*a)
    x2 = (-b + sqrt(discriminant)) / (2*a)
elif discriminant == 0:
    x1 = -b / (2*a)
    x2 = x1
else:
    x1 = (-b - csqrt(complex(discriminant))) / (2*a)
    x2 = (-b + csqrt(complex(discriminant))) / (2*a)

# Показываем результат
print("x1 =", x1)
print("x2 =", x2)
x1 = 2.0
x2 = 2.0
# Задаём коэффициенты (D < 0)
a = 5
b = 1
c = 2

# Находим дискриминант
discriminant = b*b - 4*a*c

# Находим корни
if discriminant > 0:
    x1 = (-b - sqrt(discriminant)) / (2*a)
    x2 = (-b + sqrt(discriminant)) / (2*a)
elif discriminant == 0:
    x1 = -b / (2*a)
    x2 = x1
else:
    x1 = (-b - csqrt(complex(discriminant))) / (2*a)
    x2 = (-b + csqrt(complex(discriminant))) / (2*a)

# Показываем результат
print("x1 =", x1)
print("x2 =", x2)
x1 = (-0.1-0.6244997998398398j)
x2 = (-0.1+0.6244997998398398j)

Работает! Значит ли это, что задача решена? Безусловно. Вот только есть нюанс. Вы, наверняка, заметили, что для решения одной и той же задачи нам пришлось писать один и тот же код 3 раза. Это очень плохо, ведь это значит, что мы ничего не автоматизировали. Действительно, мы должны каждый раз менять код. Следовательно, мы рано или поздно ошибёмся. Непорядок! Данная задача проста, но таких простых задач вы, быть может, больше никогда не встретите. И в настоящих (“жизненных”) задачах кода будет гораздо больше и он будет сложнее.

Возьмём ум в кулак и автоматизируем эту задачу — проведём рефакторинг кода!

Рефакторинг#

Рефакторинг — это изменение (в лучшую сторону) внутренней структуры программы и/или её кода без изменения сути этой программы: программа имеет всё тот же интерфейс (“обёртку” для взаимодействия с пользователем) и решает ту же задачу. Рефакторинг необходим исключительно для удобства поддержания и развития программного продукта.

Пока что наша программа никак не приспособлена для пользователя. Вспомните свой опыт использования компьютера. Как часто вам приходится лезть в код программы (например, Word’а или интернет-браузера)? Конечно, вы в него не лазили и просто не сможете это сделать (если вы не разработчик в соответствующей компании). Так почему наша программа должна предполагать наличие пользователя-Python-программиста? Причин для этого нет — мы же решаем квадратное уравнение. Вряд ли школьник 8 класса скажет нам спасибо за такую программу, ради которой ему нужно поучить информатику!

Более того, нам самим не по душе такой подход. Переписывание кода — это труд. А переписывание его при изменении входных данных — это бесценный (то есть неоплачиваемый) труд. Исправим ситуацию!

И начнём мы с того, что сведём код решения квадратного уравнения (расчёт дискриминанта в отдельную функцию). Назовём эту функцию solve. Пусть на вход она принимает коэффициенты квадратного уравнения, а на выходе выдаёт пару корней уравнения. Вот, что мы получим:

def solve(a, b, c):
    discriminant = b*b - 4*a*c
    if discriminant > 0:
        x1 = (-b - sqrt(discriminant)) / (2*a)
        x2 = (-b + sqrt(discriminant)) / (2*a)
    elif discriminant == 0:
        x1 = -b / (2*a)
        x2 = x1
    else:
        x1 = (-b - csqrt(complex(discriminant))) / (2*a)
        x2 = (-b + csqrt(complex(discriminant))) / (2*a)
    print("x1 =", x1)
    print("x2 =", x2)

Теперь можно вызвать эту функцию так:

# Задаём коэффициенты
a, b, c = 1, 2, -3

# Вызываем решатель квадратного уравнения
solve(a, b, c)
x1 = -3.0
x2 = 1.0

Или и вовсе в одну строку:

solve(1, 2, -3)
x1 = -3.0
x2 = 1.0

Или даже так:

solve(a=1, b=2, c=-3)
x1 = -3.0
x2 = 1.0

Можно даже передать аргументы функции в разном порядке:

solve(b=2, c=-3, a=1)
x1 = -3.0
x2 = 1.0

Important

Мы сделали одну распространённую среди новичков ошибку. В функцию solve мы поместили вывод корней в консоль функцией print. Функция print является функцией с побочным эффектом. Она выводит текст на экран — это и есть побочный эффект.

Есть ещё так называемые чистые функции (привет, IT-шовинизм), коими является подавляющее большинство. Они не меняют никакие данные в файлах, ничего не выводят на экран и не творят всякую “дичь”. Вместо этого они принимают на вход данные и возвращают результат своей работы. При этом результат одинаков для одних и тех же данных в любой день лунного календаря и не зависит от расположения звёзд на небе (если поблизости от вас нет чёрной дыры или какой-нибудь нейтронной звезды с мощным жёстким излучением).

Так вот, мы нарушили важное правило (рекомендацию) в программировании — не стоит плодить функции с побочным эффектом. Это вредно по той причине, что побочные эффекты побочны именно тем, что они выходят за рамки программы. То есть потенциально их может увидеть и испытать на себе их (зачастую нехорошее) действие любой пользователь.

И представьте, что выводить что-либо на экран запрещается. Выводить информацию можно в файл. Тогда вам опять же нужно лезть в код программы и менять код функции решения квадратного уравнения. И с какой стати вообще функция решения уравнения должна работать с файлами и вообще выводить что-либо куда-либо? Вот именно — она этого делать не должна!

“Очистим” нашу функцию! А именно, уберём принтинги и вернём корни:

def solve(a, b, c):
    # Находим дискриминант
    discriminant = b*b - 4*a*c
    # Находим корни
    if discriminant > 0:
        x1 = (-b - sqrt(discriminant)) / (2*a)
        x2 = (-b + sqrt(discriminant)) / (2*a)
    elif discriminant == 0:
        x1 = -b / (2*a)
        x2 = x1
    else:
        x1 = (-b - csqrt(complex(discriminant))) / (2*a)
        x2 = (-b + csqrt(complex(discriminant))) / (2*a)
    return x1, x2

И это далеко не предел совершенства. Функцию solve можно сделать более лаконичной:

def solve(a, b, c):
    discriminant = b*b - 4*a*c
    if discriminant >= 0:
        return (
            (-b - sqrt(discriminant)) / (2*a),
            (-b + sqrt(discriminant)) / (2*a)
        )
    return (
        (-b - csqrt(complex(discriminant))) / (2*a),
        (-b + csqrt(complex(discriminant))) / (2*a)
    )
  1. Мы вычислили дискриминант и сразу проверяем более сложное условие \(D \ge 0\). Ведь и при \(D = 0\) мы возвращаем также два (одинаковых) корня. Тем самым мы убрали elif.

  2. В теле условия if discriminant >= 0 мы поместили оператор возврата значения return без создания дополнительных переменных x1 и x2.

  3. Поскольку в случае выполнения условия if discriminant >= 0 будет выполнено его тело, то после оператора return будет осуществлён выход из функции solve. Это значит, что весь последующий код не будет выполнен. Тем самым мы можем убрать else, оставив лишь оператор return для случая комплексных корней, ведь эта часть кода будет выполнена, если не выполнится вышестоящее условие if.

Теперь работа программы выглядит так:

# Импорты опущены - они те же самые

solution = solve(1, 2, -3)

Но теперь не выводится информация на экран. Ни и отлично! Мы сами сделаем это с лёгкостью:

print(solution)
(-3.0, 1.0)

Вывод не так информативен, как был прежде. Но и это легко исправить!

Функция solve возвращает кортеж значений. Кортеж — это неизменяемый тип данных, способный хранить в себе несколько значений. Его неизменяемость заключается в том, что вы не можете изменить ни значение отдельного его элемента, ни длину самого кортежа.

Зная, что переменная solution есть кортеж, мы можем делать следующие вещи:

# Вариант №1
print("Вариант №1")
print("x1 =", solution[0])
print("x2 =", solution[1])

# Вариант №2
x1, x2 = solution   # распаковка кортежа
print("Вариант №2")
print("x1 =", solution[0])
print("x2 =", solution[1])

# Вариант №3
x1, x2 = solve(1, 2, -3)    # та же распаковка
print("Вариант №3")
print("x1 =", solution[0])
print("x2 =", solution[1])
Вариант №1
x1 = -3.0
x2 = 1.0
Вариант №2
x1 = -3.0
x2 = 1.0
Вариант №3
x1 = -3.0
x2 = 1.0

В результате рефакторинга наша программа приобрела следующий вид:

from cmath import sqrt as csqrt
from math import sqrt


def solve(a, b, c):
    discriminant = b*b - 4*a*c
    if discriminant >= 0:
        return (
            (-b - sqrt(discriminant)) / (2*a),
            (-b + sqrt(discriminant)) / (2*a)
        )
    return (
        (-b - csqrt(complex(discriminant))) / (2*a),
        (-b + csqrt(complex(discriminant))) / (2*a)
    )


# Коэффициенты
a, b, c = 1, 2, -3
# Решение
x1, x2 = solve(a, b, c)
# Показ результатов
print("x1 =", x1)
print("x2 =", x2)
x1 = -3.0
x2 = 1.0

Хорошо, код мы отредактировали. Но всё ещё не избавили пользователя от необходимости лезть в файл с кодом, чтобы изменить исходные данные.

Чтобы это исправить, нам следует разработать интерфейс программы. Приступим!

Интерфейс#

Из повседневного опыта работы с компьютером вы знаете, что такое интерфейс. Большинство из вас (или даже все) привыкли к окнам в операционной системе Windows. Это и есть интерфейсы различных программ для вас как пользователя, а именно, графические интерфейсы. Такие интерфейсы довольно сложны в разработке и требуют понимания ряда нетривиальных концепций программирования (объектно-ориентированное программирование, паттерны разработки оконных приложений и т.д.).

Довольно странно заморачиваться оконным интерфейсом для простых программ и программ, не предназначенных для настолько “искушённого” пользователя. В мире Linux правит бал терминал, в котором пользователь пишет различные строки с командами (командные строки). Что-то типа такого: “копировать файл1.txt в директорию важные_файлы/”. На самом деле такая командная строка выглядит так:

$ cp файл.txt важные_файлы/

В мире GNU/Linux (да и мир Windows движется туда же) широко распространён интерфейс командной строки (CLI — Command Line Interface). Причём большое количество программ имеют как графический, так и интерфейс командной строки (свобода выбора и удобство!).

Для примера посмотрим на CLI стандартной программы cp GNU/Linux, предназначенной для копирования файлов. Для того, чтобы увидеть её интерфейс, в терминале вызовите cp с флагом показа справки --help:

$ cp --help

Вы получите следующую информацию:

$ cp --help
Usage: cp [OPTION]... [-T] SOURCE DEST
  or:  cp [OPTION]... SOURCE... DIRECTORY
  or:  cp [OPTION]... -t DIRECTORY SOURCE...
Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY
...

Ту же информацию можно получить командой man cp. Так что же нам говорит справка? Фактически, она полностью описывает то, как пользоваться этой программой.

Что касается интерфейса. Он показан в секции Usage. Согласно описанию, программу cp можно использовать тремя способами:

  1. Копировать один файл SOURCE в директорию или файл DEST.

  2. Копировать несколько файлов SOURCE... в директорию DEST.

  3. То же, что и в предыдущем пункте, но указание флага -t позволяет указать целевую директорию DEST перед указанием копируемых файлов SOURCE....

При этом во всех трёх случаях возможно указание необязательных (опциональных) [OPTION] параметров.

Почитайте справку. Оказывается, такая незамысловатая программа как cp имеет довольно развитый и многофункциональный CLI.

Можем ли мы сделать нечто подобное для нашего скрипта? Конечно!

Разрабатываем интерфейс командной строки#

Помните — любая работа начинается с постановки цели и формулирования соответствующей задачи.

Наша цель — сделать работу с нашим решателем квадратного уравнения удобной.

Задача состоит в том, чтобы сделать CLI, позволяющий вызывать нашу программу, передавая ей коэффициенты квадратного уравнения:

$ solve_quadric_eq 1 2 -3
x1 = -3.0
x2 = 1.0

Приступим. Стоит отметить, что в Python существует по меньшей мере четыре способа решения такой задачи. Рассмотрим пару из них.

Использование пакета sys#

# Импортируем
import sys

from cmath import sqrt as csqrt
from math import sqrt


def solve(a, b, c):
    discriminant = b*b - 4*a*c
    if discriminant >= 0:
        return (
            (-b - sqrt(discriminant)) / (2*a),
            (-b + sqrt(discriminant)) / (2*a)
        )
    return (
        (-b - csqrt(complex(discriminant))) / (2*a),
        (-b + csqrt(complex(discriminant))) / (2*a)
    )


if __name__ == "__main__":
    # Получаем коэффициенты из командной строки
    args = sys.argv
    a, b, c = float(args[1]), float(args[2]), float(args[3])
    # Решение
    x1, x2 = solve(a, b, c)
    # Вывод на экран
    print("x1 =", x1)
    print("x2 =", x2)

Что получилось:

  • Функция solve нисколько не изменилась. Иначе говоря, сама наша программа не изменилась.

  • Мы подключили пакет для работы с системными вызовами sys. С её помощью посредством sys.argv мы получили доступ к аргументам командной строки, которые сохранили в переменной args. args хранит список (именно list) аргументов: args[0] — имя вызванного скрипта (программы); args[1]...[3] — переданные параметры (коэффициенты). При этом каждый элемент имеет тип строки (str), поэтому необходимо их преобразование в числа с плавающей точкой float.

  • Далее программа работает, как и ранее.

Теперь наш пользователь (школьник) может решить любое квадратное уравнение без изменения исходного кода. Ему достаточно скачать (откуда-нибудь) файл скрипта solve_quadric_eq.py и вызвать его через интерпретатор Python с указанием параметров через пробел 1 2 -3:

$ python3 solve_quadric_eq.py 1 2 -3
x1 = -3.0
x2 = 1.0

Более того, можно немного упростить вызов, если в самой первой строке скрипта указать специальный комментарий с указанием пути к интерпретатору Python

#!/usr/bin/python3

и сделать файл этого скрипта исполняемым, например, следующей командой:

$ chmod +x solve_quadric_eq.py

Теперь вызвать скрипт из командной строки можно так:

$ ./solve_quadric_eq.py 1 2 -3

Note

Можно сделать вызов и такой командой $ solve_quadric_eq 1 2 -3. Однако это требует некоторых дополнительных знаний, которые пока могут быть излишними, но вы обязательно их обретёте в процессе учёбы и практики программирования.

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

  1. Если пользователь по ошибке укажет более трёх чисел, то программа рухнет с ошибкой, мало что говорящей пользователю. Из-за этого он может не понять, что не так. И скорее всего подумает, что ошибка в самой программе, а не с его стороны.

  2. В принципе \(a x^2 = 0\) — это тоже квадратное уравнение. Как и \(a x^2 + b x = 0\) или \(a x^2 + c = 0\). Поэтому коэффициенты \(b\) и \(c\) можно сделать нулевыми по умолчанию, чтобы не тратить время на их указание.

  3. Нашей программе не хватает пользовательской справки, чтобы пользователь быстро и легко узнал всё о её интерфейсе и возможностях.

Уйти от этих недостатков с помощью sys довольно сложно. Но Python на то и Python, чтобы предложить несколько готовых решений. Рассмотрим стандартный пакет argparse.

Разрабатываем интерфейс с помощью argparse#

#!/usr/bin/python3

# Импортируем
from argparse import ArgumentParser
from cmath import sqrt as csqrt
from math import sqrt


def solve(a, b, c):
    discriminant = b*b - 4*a*c
    if discriminant >= 0:
        return (
            (-b - sqrt(discriminant)) / (2*a),
            (-b + sqrt(discriminant)) / (2*a)
        )
    return (
        (-b - csqrt(complex(discriminant))) / (2*a),
        (-b + csqrt(complex(discriminant))) / (2*a)
    )


if __name__ == "__main__":
    # Получаем коэффициенты из командной строки
    parser = ArgumentParser(
        "solve_quadric_eq",
        description="Let you solve any quadric equation a*x^2 + b*x + c = 0"
    )
    parser.add_argument(
        "a",
        type=float,
        help="The first coefficient of the equation"
    )
    parser.add_argument(
        "b",
        nargs="?",
        type=float,
        default=0,
        help="The second coefficient of the equation (default 0)"
    )
    parser.add_argument(
        "c",
        nargs="?",
        type=float,
        default=0,
        help="The third coefficient of the equation (default 0)"
    )
    parser.add_argument(
        "-B",
        type=float,
        help="The second coefficient of the equation (default 0)"
    )
    parser.add_argument(
        "-C",
        type=float,
        help="The third coefficient of the equation (default 0)"
    )
    
    args = parser.parse_args()
    a, b, c = args.a, args.b, args.c
    if args.B is not None:
        b = args.B
    if args.C is not None:
        c = args.C
    # Решение
    x1, x2 = solve(a, b, c)
    # Вывод на экран
    print("x1 =", x1)
    print("x2 =", x2)

Чего мы добились:

  1. Теперь у нас есть справка по интерфейсу программы:

    $ ./solve_quadric_eq.py -h
    usage: solve_quadric_eq [-h] [-B B] [-C C] a [b] [c]
    
    Let you solve any quadric equation a*x^2 + b*x + c = 0
    
    positional arguments:
      a           The first coefficient of the equation
      b           The second coefficient of the equation (default 0)
      c           The third coefficient of the equation (default 0)
    
    options:
      -h, --help  show this help message and exit
      -B B        The second coefficient of the equation (default 0)
      -C C        The third coefficient of the equation (default 0)
    
  2. Можно указать либо коэффициент \(a\), либо два коэффициента \(a\) и \(b\), либо все \(a\), \(b\) и \(c\):

    $ ./solve_quadric_eq.py 1
    x1 = 0.0
    x2 = 0.0
    $ ./solve_quadric_eq.py 1 2
    x1 = -2.0
    x2 = 0.0
    $ ./solve_quadric_eq.py 1 2 3
    x1 = (-1-1.4142135623730951j)
    x2 = (-1+1.4142135623730951j)
    
  3. Можно указывать коэффициенты \(b\) и \(c\) в разном порядке:

    $ ./solve_quadric_eq 1 -C 2
    x1 = -1.4142135623730951j
    x2 = 1.4142135623730951j
    $ ./solve_quadric_eq 1 -C 2 -B 3
    x1 = -2.0
    x2 = -1.0
    
  4. Если хотите сохранить результат в файл, достаточно перенаправить поток вывода в нужный файл, например:

    $ ./solve_quadric_eq 1 -C 2 -B 3 > answer.txt
    

    Внутри файла answer.txt вы увидите тот же вывод, что ранее был в консоли.

  5. Понятные сообщения об ошибке пользователя:

    $ ./solve_quadric_eq.py 1 2 3 777
    usage: solve_quadric_eq [-h] [-B B] [-C C] a [b] [c]
    solve_quadric_eq: error: unrecognized arguments: 777
    

Вот теперь можно сказать: “Мы автоматизировали поиск корней квадратного уравнения с любыми коэффициентами!”

Note

Заметьте, теперь мы совсем не лезем в исходный код, чтобы решать различные квадратные уравнения.

Однако возможна и дальнейшая автоматизация. Например, можно реализовать чтение исходных данных скрипта (коэффициентов уравнения) из различных файлов. Работой с файлами займёмся в следующем разделе.