Запуск python и python-скрипт на компьютере

Bash (Bourne Again Shell)

Наиболее часто используемая командная оболочка по умолчанию в операционных системах GNU/Linux. Она включает в себя простой язык программирования, который позволяет при помощи условных операторов и операторов цикла использовать утилиты и программы операционной системы для написания как простых, так и сложных скриптов.

В этом плане Bash, несомненно, обладает некоторыми преимуществами, в частности, универсальностью и доступностью. Для того, чтобы написать скрипт на Bash, установка дополнительных пакетов не требуется. Достаточно создать файл вида script_name.sh с последовательно исполняемыми операциями и запустить его, либо добавить в качестве задачи планировщика cron.

Стоит отметить, что возможности командного интерпретатора зачастую используются не полностью. Многие администраторы выбирают Bash для написания простых или средних по сложности скриптов. В крупных проектах, где есть специфические задачи и требуется работа с разнообразными входными данными, многомерными массивами и сокетами больше доверяют Perl, Python или Ruby.

Отчасти это связано с проблемами переносимости bash-скриптов на другие платформы, (например, Windows), отчасти с тем, что Bash воспринимается скорее как средство автоматизации работы с файлами и утилитами, чем полноценный скриптовый язык, даже несмотря на наличие в арсенале sed и awk. Ещё одним минусом Bash является то, что при выполнении скрипта каждая запущенная с его помощью утилита создаёт свой процесс, что отражается на скорости выполнения и уровне использования ресурсов системы.

Функция модуля клавиатуры

В этом модуле есть много функций, которые можно использовать для имитации действий клавиатуры.

  • keyboard.write(message, )- пишет сообщение с задержкой или без нее.

  • keyboard.wait(key) — блокирует программу до тех пор, пока не будет нажата клавиша. Ключ передается в виде строки («пробел», «esc» и т.д.)

  • keyboard.press(key)- нажимает клавишу и удерживается до вызова функции release(key)

  • keyboard.release(key)- выпускает ключ.

  • keyboard.send(key)- нажимает и отпускает клавишу.

  • keyboard.add_hotkey(hotkey, function)- создает hotkey, которая при нажатии выполняет function.

  • keyboard.record(key)- записывает активность клавиатуры до нажатия key.

  • keyboard.play(recorded_events, ) — воспроизводит события, записанные with keyboard.record(key) функция, с дополнительным speed_factor.

Тем не менее, мы рассмотрим все это. Вот быстрый пример:

Приветственное сообщение появляется на экране в терминале, как будто вы его написали. Вы можете очень легко автоматизировать команду и создать для нее псевдоним горячей клавиши. Вот (грубый) пример выхода из REPL Python, написания команды curl:

Откуда взялась статья?

Одним из важных составляющих в области ИИ является обработка текстов на естественном языке. В процессе изучения данной тематики я начал задавать себе вопросы, которые в конечном итоге привели меня к изучению кодировок, представлению текстов в памяти, как они преобразуются, приводятся к нормальной форме. Я плохо понимал эту тему в начале, потребовалось немало времени и мозгового ресурса, чтобы понять, принять и запомнить некоторые вещи. Написанием данной статьи я хочу облегчить жизнь людям, которые столкнутся с необходимостью чтения и обработки текстов на Python и самому закрепить изученное. А некоторыми полезными поинтами своего изучения я постараюсь поделиться в данной статье.

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

Пишем скрипт для рисования

В данном примере мы напишем скрипт, который будет рисовать дерево. Для работы с графикой в открытом доступе существует специальная Python-библиотека simple_draw. Чтобы установить ее, необходимо открыть командную строку (cmd) и прописать в ней команду pip install simple_draw.

Для начала давайте представим, из чего состоит структура дерева. Это ствол и ветки. В нашей программе дерево будет строиться из векторов — направленных отрезков. Попробуем нарисовать вектор. Перейдем в редактор, создадим новый файл draw.py и пропишем следующий код:

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

Далее создаем переменную point (точка) и с помощью метода (функции) get_point задаем начальную точку, из который будет выходить вектор, —600 пикселей от левого края экрана и 5 пикселей от низа экрана.

Чтобы создать объект Vector, нужно задать ему такие параметры, как точка начала вектора — point, угол отклонения — angle (90 градусов), длина — length (100 пикселей) и толщина линии — width (3 пикселя). Как видно из кода, все эти переменные можно записать в одну строчку.

Переменная vector_1 будет содержать в себе объект — вектор, а чтобы отрисовать его в окне, применим к нему метод draw (рисовать). Сохраним и запустим скрипт.

Представим, что мы отрисовали ствол дерева. Теперь попробуем создать еще несколько векторов, чтобы нарисовать ветви. У дерева может быть огромное количество веток, поэтому придется создавать и большое количество векторов. Такой код будет слишком громоздким и длинным. Чтобы этого избежать, автоматизируем процесс рисования векторов и создадим функцию branch, принимающую на вход параметры point, angle, length и width, которая и будет рисовать ветви.

Данная функция создает вектор с теми параметрами, которые ей передаются в скобках, отрисовывает его, а затем возвращает конечную точку отрисованного вектора (vector.end_point), угол отклонения, который на30 градусов меньше предыдущего (angle –30), длину вектора, немного меньшую исходной (length*0.8) и ширину (width). Попробуем с ее помощью создать несколько новых ветвей.

Мы нарисовали4 вектора. Каждый последующий вектор исходит от конца предыдущего и отличается длиной и углом отклонения, тем самым формируя изгиб ветви дерева. Но если мы снова представим реальное дерево, то чтобы отрисовать его, потребуется еще множество векторов. Задача программиста — написать как можно более компактный, универсальный и красивый код.

Поэтому сейчас пора освоить такую важную вещь, как рекурсия. Рекурсия — это когда функция внутри своего тела вызывает саму себя. Сократим немного код и перепишем функцию.

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

Теперь сделаем так, чтобы с конца каждой ветви дерева исходили вправо и влево другие ветви, меньшего размера. Для этого в тело функции нужно добавить еще один вызов самой себя, в котором параметр angle будет увеличиваться на30 градусов. Таким образом ветви будут отрисовываться и вправо (angle –30), и влево (angle +30).

Добавим немного красоты нашему дереву и сделаем так, чтобы цвет каждой ветви генерировался случайным образом. Для этого внутри функции vector.draw() в скобках укажем параметр simple_draw.random_color() — это функция, которая возвращает случайный цвет.

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

Запустим на выполнение и получим красивое, разноцветное дерево.

Как видите, небольшая функция за нас сделала всю работу. Изменив ее параметры и немного «поиграв» с кодом, можно добиться различных форм и видов деревьев.

Как писать расширения на Си

В качестве примера реализуем классическую функцию , которая принимает число n и возвращает соответствующее число в последовательности Фибоначчи, и сравним производительность версий на Питоне и Си.

Прежде всего нам понадобится API для Питона,  — Си, который содержит всё необходимое для взаимодействия с Питоном.

Установка API:

  • На Линуксе обычно нужно установить пакет или (если он еще не установлен). (В некоторых дистрибутивах название пакета может отличаться.)

  • В стандартной установке Windows Питон по умолчанию уже есть.

  • В macOS Питон тоже должен быть установлен — если это не так, запустите .

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

Прежде чем писать код расширения, необходимо включить пару основных определений и объявлений:

Эти строки рекомендуется поместить в начало файла — для .

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

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

Определение методов модуля

Каждый экспортированный метод представляет собой структуру, содержащую:

  • Имя экспортируемого метода (у нас это «»).

  • Фактически экспортируемый метод ().

  • Тип принимаемых методом аргументов (у нас — ). Из документации по : «Это типичное соглашение о вызовах с методами типа . Функция ожидает два значения . Первый — это объект self для методов; для функций модуля это объект модуля. Второй параметр (часто его называют ) — объект кортежа, представляющий все аргументы».

  • И с описанием метода.

Определение модуля

Модуль представлен в виде структуры (см. код выше). Код должен быть вполне понятен — вопросы может вызвать разве что аргумент , для которого мы задали значение . Выдержка из документации:

Функция инициализации модуля

При импорте модуля вызывается и инициализирует его

Обратите внимание, что имя функции должно начинаться с и заканчиваться именем модуля — то есть, в нашем примере это будет

Здесь описаны лишь несколько возможностей API для Питона — подробнее можно почитать на странице документации.

Как запускать Python-скрипты?

Для запуска Python-скрипта с помощью командной строки сначала нужно сохранить код в локальный файл.

Возьмем в качестве примера файл, который был сохранен как python_script.py. Сохранить его можно вот так:

Сохранить скрипт в текстовом редакторе достаточно легко. Процесс ничем не отличается от сохранения простого текстового файла.

Но если использовать командную строку, то здесь нужны дополнительные шаги. Во-первых, в самом терминале нужно перейти в директорию, где должен быть сохранен файл. Оказавшись в нужной папке, следует выполнить следующую команду (на linux):

После нажатия Enter откроется интерфейс командной строки, который выглядит приблизительно следующим образом:

Теперь можно писать код и с легкостью сохранять его прямо в командной строке.

Стилизация print

icecream

Для форматирования вывода существует одна удобная библиотека под названием icecream. Она помогает упростить написание логов или принтов для отладки. Рассмотрим пример её работы:

Чтобы подключить информацию о том, в каком месте программы происходит вывод, необходимо добавить всего лишь один аргумент в конфигурации модуля:

Это помогает более точно понять в каком месте происходит сбой в работе программы:

Также можно поменять префикс, который добавляется в начале строки, по дефолту он задан “ic|”. Удобно добавить время для вывода, чтобы видеть в какой момент времени и сколько занимал переход от одного принта к другому.

Если у вас уже имеются расставленные принты в коде, то легко можно переприсвоить print на ic:

Рассмотрим пример вывода более сложных структур, например, словарей:

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

Также эта библиотека предоставляет возможность стилизовать вывод в зависимости от предоставляемых данных. Например, если есть необходимость дополнительно оформлять текст ошибки (Exception) или есть желание дополнительно выводить тип данных:

colorama

Еще одна полезная библиотека — colorama, она позволит раскрашивать текст в консоли. Её удобно использовать совместно с библиотекой icecream. Рассмотрим пару примеров:

Функции write() и wait() клавиатуры

Команда write() записывает сообщение, как мы видели ранее, с необязательной задержкой при запуске. Если задержка не установлена, запись выполняется мгновенно. Это очень хорошо сочетается с функцией wait (), которая ожидает нажатия определенной клавиши.

Например, мы можем создать импровизированный макрос, привязанный, скажем, к 1, который отвечает на этот ввод новым сообщением

Обратите внимание, что вместо этого есть фактический способ создания горячих клавиш, который мы рассмотрим позже

Мы создадим бесконечный цикл True, чтобы проверить, нажата ли клавиша, и вы можете запустить сценарий в фоновом режиме:

Примечание: Специальные символы не поддерживаются этой функцией, поэтому, если вы добавите, скажем, ! — вы получите исключение остановки.

Шаг 5

Установим Python и nano

Для установки Python’а пишем в терминале:

Теперь у нас установлен 2 и 3 Python.

За время работы над статьей, я открыл для себя еще один текстовый редактор nano, который приглянулся мне больше чем vim, давайте его установим:

Пользоваться им проще чем vim’ом, и nano имеет более дружественный интерфейс. На Android устройстве все же удобнее vim.

HelloWorld на Python в Termux

По большому счету можно было обойтись и без этого пункта, но поставить Python в Termux и не написать HelloWorld, на мой взгляд, моветон.

Я не ставлю своей целью учить кого-либо Python’у, так что не знающие могут просто скопировать код (или начать изучать самостоятельно, благо литературы хватает), а знающие могут и сами что-нибудь наваять. А я «под шумок» еще покажу способ вводить текст в терминале без редактора.

Если в процессе ввода вы не заметили ошибку и уже нажали Enter, то перейти на строку выше не получится, для этого закончите ввод нажав Ctrl + D (можно вообще прервать Ctrl + Z) и повторите все с начала. Поскольку мы использовали ‘>’ то файл будет переписан полностью. По этой причине не рекомендую использовать такой метод ввода, если вы не уверены что напишете код сразу без ошибок.

0x02. Комментирование вызова функции

От общих слов перейдем к конкретным примерам.

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

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

Расставим комментарии в местах обращений к функции . Как видно из рисунка, в текущей базе известно 11 обращений к .

Общий алгоритм для добавления комментариев будет таким:

  • получить все кросс-ссылки на функцию ;
  • в каждом месте обращения к составить список аргументов;
  • составить строку комментария;
  • добавить комментарий.

Для выполнения этих действий потребуются следующие функции и классы:

  • — создаёт генератор, который возвращает объекты-ссылки из кода на указанный адрес. Параметр (значения 0/1) задаёт необходимость учитывать ссылки, которые сформированы за счёт простого перехода от инструкции к инструкции. В нашем случае ;
  • — возвращает адрес предыдущей инструкции относительно указанного адреса, это необходимо для прохода вверх по коду для поиска аргументов;
  • — возвращает значение n-го операнда по указанному адресу. Если операнд является регистром, то возвращается номер регистра в соответствии с текущей процессорной архитектурой. Для архитектуры ARM номера регистров очевидны:
    • R0 — 0;
    • R1 — 1;
    • R2 — 2 и так далее;
  • — возвращает тип n-го операнда по указанному адресу. Основные типы операндов:
    • — инструкция без операнда (например, NOP);
    • — регистр;
    • — адрес в памяти;
    • — составной адрес ,
    • — составной адрес ;
    • — число-константа;
    • — FAR-адрес;
    • — NEAR-адрес;
    • другие типы операндов зависят от процессорной архитектуры;
  • — возвращает строковое представление операнда;
  • — добавляет комментарий по указанному адресу (см. ниже).

Аргументы функции

Поскольку в архитектуре ARM аргументы передаются в функцию через регистры (R0-R3), то необходимо:

  • пройти вверх от точки обращения к функции;
  • найти инструкции, где в регистры R0, R1, R2 заносятся данные (функция memcpy принимает 3 аргумента);
  • если в регистры заносится число или адрес, нужно вернуть hex-представление этого числа, для всех остальных случаев вернуть просто текстовое представление операнда.

Комментарии в IDA

Комментарии в базе IDA бывают трех типов:

Простые комментарии — отображаются только в той строке, где они установлены. Добавляются функцией с аргументом :

Повторяемые комментарии (repeatable) — помимо основной строки отображаются ещё и там, где есть ссылка на строку с комментарием. Добавляются функцией с аргументом :

Многострочные комментарии в коде () — устанавливаются функцией :

Для нашего случая подходят простые неповторяемые комментарии.

Nuitka

Уже в процессе работы над статьей, я узнал про еще один проект с аналогичными целями. Механизм работы Nuitka сильно напоминает описанный выше. Разница заключается в том, что Nuitka компилирует Python модуль в С++ код, который также собирается в СPython Extension. Дополнительно существует возможность собрать весь проект в один исполняемый файл, тогда уже сам CPython подключается к проекту как динамическая библиотека libpython.

Nuitka пока не учитывает аннотацию типов, поэтому результирующий код и скорость работы не зависят от наличия аннотаций. Полученная же скорость в моем тесте соответствует результату mypy на не аннотированном коде.

Бенчмарк

Так как одной из целей является ускорение, необходимо оценить, насколько быстро работает скомпилированный код. В качестве бенчмарка будем использовать pyperfomance. К сожалению, pyperfomance не подошел для Cython и Pythran, потому что не позволяет визуализировать все возможности языка. Ускорения для Cython без модификации кода получить не удалось, а Pythran не умеет в пользовательские классы. Для них воспользуемся вычислением числа пи:

Эксперименты будем проводить на процессоре Intel Core i7 10510U. На CPython 3.9.7 время вычисления числа пи до 100.000.000 знака заняло 5.82 секунды.

Как выполнять код интерактивно

Есть больше 4 способов запустить Python-скрипт интерактивно. Рассмотрим их все подробно.

Использование import для запуска скриптов

Импорт модулей для загрузки скриптов и библиотек используется постоянно. Можно даже написать собственный скрипт (например code1.py) и импортировать его в другой файл без необходимости повторять то же самое.

Вот как нужно импортировать code1.py в новом скрипте.

Копировать

Но таким образом импортируется все содержимое файла code1.py. Это не проблема до тех пор, пока не появляется необходимость, в том, чтобы код был оптимизирован и быстро работал.

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

Вот как это обычно делается.

Копировать

Теперь появляется возможность использовать в новом файле так, будто бы эта функция была написана здесь.

Использование importlib для запуска кода

из importlib позволяет импортировать и исполнять другие Python-скрипты.

Это работает очень просто. Для скрипта code1.py нужно сделать следующее:

Копировать

И нет необходимости добавлять .py в .

Разберем случай, когда есть сложная структура папок, и нужно использовать importlib. Предположим, что структура следующая:

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

Так, для запуска скрипта level3.py можно написать так:

Копировать

Запуск кода с помощью runpy

Модуль ищет и исполняет Python-скрипт без импорта. Он также легко используется, ведь достаточно просто вызывать имя модуля в .

Вот как, например, выполнить code1.py с помощью runpy.

Копировать

Запуск кода динамически

Рассмотрим функцию , которая также используется для динамического выполнения скриптов. В Python2 эта функция была инструкцией.

Вот как она помогает выполнять код динамически на примере строки.

Копировать

Однако этот способ уже устарел. Он медленный и непредсказуемый, а Python предлагает массу других вариантов.

Как ускорить код на Питоне?

Обычно производительности Питона достаточно — если не приходится выполнять «тяжелые» вычисления, в случае которых как раз и могут пригодиться расширения на Cи.

Многие популярные модули написаны на Си или Cи++ (например, numpy, pandas, tensorflow и т. д.) — для повышения производительности и (или) расширения низкоуровневой функциональности.

О чем важно знать:

  • Расширения на Си работают только на реализации Cpython, но поскольку по умолчанию используется именно она, проблемы в этом быть не должно.

  • Для применения этого подхода рекомендуется иметь базовые знания Си. Но если вы знаете только Питон, статья тоже будет вполне вам понятна.

Создаём инстанс Ubuntu

1. Кликните по кнопке “Create Instance” (обведена на картинке выше).

2. Под изображением c выбором вашего инстанса выберите Linux/Unix.

3. Выберите “OS Only”.

4. Выберите Ubuntu 18.04.

шаги создания инстанса ubuntu

5. Выберите тариф для своего инстанса. Для этого проекта я беру самую недорогую опцию за $3.50. Она более чем подходит для запуска большинства скриптов на Python. Не забывайте, что платить за первый месяц не нужно.

6. Дайте название инстансу. Для своего проекта я придумал “Ubuntu-автоматизация”.

7. Выберите “Create Instance”.

После выбора “Create Instance” вы вернётесь на дашборд AWS LightSail. Чтобы новый Ubuntu-инстанс появился, должно пройти несколько минут. Пока это происходит, вы будете видеть статус “Pending”, как на скриншоте ниже:

В ожидании создания

Статус сменится на значение “Running” сразу после того, как новый инстанс будет создан. Также вы увидите IP-адрес, присвоенный инстансу. Например, у моего был 3.227.241.208. Этот адрес динамический и будет меняться каждый раз после перезагрузки инстанса. В зависимости от проекта, который вы будете хранить, может понадобиться и статический IP-адрес.

Ubuntu-инстанс создан и запущен

Создаём статический IP-адрес

Можно и не создавать статический IP, разве что он нужен по требованиям вашего проекта. Я буду создавать статический IP-шник потому, что собираюсь открывать свой SQL-сервер только на нём из соображений безопасности. После первой установки я предпочитаю подключаться по SSH в моем Ubuntu-инстансе со своей локальной машины, а благодаря статическому IP этот процесс упрощается.

1. Перейдите во вкладку “Networking” на вашем дашборде Lightsail.

2. Кликните на “Create static IP”.

дашборд Networking

3. Выберите ваш сервер для Ubuntu-инстанса в “Attach to an instance”.

4. Назовите статический IP.

5. Нажмите на “Create”.

Затем вы должны увидеть ваш новый статический IP-адрес. И этот IP-адрес не будет изменяться.

Поехали дальше: 18.213.119.58 — статический IP проекта.

Автоматизация Python

Для этого проекта я буду писать скрипт на Python. Он вызывает Reddit API и собирает все новые представления с reddit.com/r/learnpython. Чтобы не растягивать повествование, я не стану рассматривать работу этого отдельного скрипта, а вы можете увидеть весь код на GitHubLink.

Сравнение с версией на «чистом» Питоне

Теперь сравним функцию с ее аналогом на Питоне. Воспользуемся встроенным модулем :

Вывод:

Как и ожидалось, функция на Си работает быстрее.

А теперь попробуем на больших числах:

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

И здесь расширения на Си могут здорово выручить: так вы поручите всю тяжелую работу производительному языку, а в качестве основного продолжите использовать Питон.

Как выполняются Python-скрипты?

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

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

Но и это еще не все.

Блок-схема выполнения кода интерпретатором

  • Шаг 1: скрипт или .py-файл компилируется, и из него генерируются бинарные данные. Готовый файл имеет расширение .pyc или .pyo.
  • Шаг 2: генерируется бинарный файл. Он читается интерпретатором для выполнения инструкций.

Это набор инструкций, которые приводят к финальному результату.

Иногда полезно изучать байткод

Если вы планируете стать опытным Python-программистом, то важно уметь понимать его для написания качественного кода

Это также пригодится для принятия решений в процессе

Можно обратить внимание на отдельные факторы и понять, почему определенные функции/структуры данных работают быстрее остальных

Оценка производительности

pympler

Потребление памяти в Python отдельная проблема, которой можно посвятить много времени, поэтому зачастую приходится следить за тем, чтобы python не сожрал всю оперативку. Для проверки памяти есть замечательный модуль pympler, который поможет не только посмотреть память, занимаемую объектом, но также поможет проследить за памятью, которую занимают отдельные классы или типы данных:

Проследим за изменением памяти, занимаемой классом A:

И в целом за памятью, занимаемой различными структурами

py-spy

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

В таком случае можно воспользоваться библиотекой py-spy, она позволяет без остановки программы проверить, сколько времени какие процессы в ней занимают. Установить библиотеку можно через pip install py-spy. Усложним код предыдущей программы, создадим дополнительный модуль sec.py:

модуль main.py:

Теперь через терминал достаточно прописать команду py-spy top — python main.py и вы будете получать информацию о времени работы каждого метода программы: