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

14 мая, в это воскресенье на Xakep.ru пройдет бесплатный вебинар по основам Python. В преддверии одноименного курса ты сможешь получить представление о том, как будут проходить занятия, а также понять, подходят ли тебе именно этот преподаватель и программа.

Заходи на страницу курса и регистрируйся для участия в бесплатном вебинаре.

Очередной поток курса «Python с нуля» начнется 23 мая 2023. Курс состоит из 14 вебинаров, и будет идти примерно полтора месяца. На курсе ты научишься основам Python, напишешь много интересных скриптов, создашь несколько Telegram-ботов, простого голосового ассистента, освоишь объектно-ориентированный подход, парсинг сайтов, разработку графического интерфейса на PyQt, и многое другое.

Если у тебя на компе есть современный дистрибутив Linux, то в него уже входит Python 3, а писать первые программы будет удобно в IDLE — простом редакторе кода, который прилагается к Python. В Ubuntu, чтобы установить его, набери в консоли:

sudo apt-get install idle3

Запустив IDLE, зайди в Options → Configure IDLE, перейди на вкладку General и поставь галочку на пункте Open Edit Window, нажми ОK и перезапусти IDLE. Теперь можно писать программы, сохранять их и запускать клавишей F5.

Также, можно установить редактор кода Visual Studio Code или PyCharm.

В Windows при установке Python обязательно отметь на первом экране установщика галочку Add to Path, чтобы можно было запускать python3 из командной строки в любом удобном месте.

Переменные

В любом языке программирования есть такая штука, как переменные. Это как в школьной алгебре: вот переменная a = 1, вот переменная b = 2. То есть это ссылки на места в оперативной памяти, где лежит значение, которое может меняться — например, когда ты пишешь после переменной знак равно (оператор присваивания) и какое-то новое значение.

a = 2
b = 2
c = a + b
print(c)

Ну, то, что print(c) — это команда, которая печатает на экране текущее значение переменной, ты уже понял. На экране гордо красуется 4. Поздравляю, два и два сложили!

А если изначально неизвестно, какие числа надо складывать? Тогда пришлось бы сперва попросить юзера ввести их в консоли и нажать Enter. Давай так и сделаем:

beer1 = input('Введи, сколько у тебя литров пива: ')
beer2 = input('Сколько пива принес друг: ')
beer3 = int(beer1) + int(beer2)
answer = 'На двоих у вас: ' + str(beer3) + ' литров пива'
print(answer)

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

Слово «функция» должно быть знакомо тебе из математики. В скобках мы пишем то, что она принимает (аргументы), а на выходе будет результат. Python сначала подменит переменную на ее текущее значение (int(a) на, скажем, int("5"), а потом функцию — на результат ее выполнения, то есть 5. Бывает, что функция ничего не возвращает, только что-то делает. Например, print() только печатает аргумент.

Окей, преобразовал строки в числа, положил их в переменную beer3, а дальше-то что за треш внутри скобок у print? Нам нужно красиво напечатать результат. Для этого складываем строки (они всегда пишутся в кавычках), поясняющие, что именно выводится на экран, а результат сложения помещаем в переменную answer.

Чтобы строки безболезненно сложились с переменной beer3, в которой лежит число, надо преобразовать его в строку функцией str() — так же как мы превращали строки в числа, только наоборот.

Вообще, типов переменных много, но суть ты уловил — чтобы производить с переменными какие-то действия, нужно их сначала привести к одному типу — к строковому, или к числовому, или еще к какому-нибудь. Если с этим не заморачиваться, Python сложит не числа, а строки и, например, введенные 2 и 3 литра пива в сумме дадут не 5, а целых 23. Хорошо бы так было в реальности!

Вот еще примерчик, рассчитывающий, сколько тебе осталось пить пиво, исходя из средней продолжительности жизни в России:

age = input('Введи, сколько тебе лет: ')
max_age = 73 - int(age)
print('Осталось примерно: ' + max_age + " лет")

Здесь мы вызываем функцию input(), чтобы получить значение, вычитаем его из 73 (средняя продолжительность жизни россиянина), не забыв превратить строку в число, а потом печатаем результат. Внутри print() можно выводить значения разных типов, если написать их через запятую.

Итак, ты узнал, что такое целочисленные и строковые переменные, что эти типы можно преобразовывать друг в друга командами int() и str(). К тому же теперь ты умеешь получать переменные от пользователя с помощью функции input('Введите что-то') и печатать результаты с помощью функции print().

Условия

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

beer = input('Введите Yes, если пиво есть, и No, если пива нет: ')
if beer.lower() == 'yes':
    answer = 'Ты взломаешь Пентагон'
else:
    answer = 'Ты сломаешь свой мозг'
print(answer)

На английском if значит «если», а else — «иначе» или «в противном случае». В строчке после if идет условие, которое мы проверяем. Если оно верно, выполняется первый блок кода (он отделен четырьмя пробелами вначале). Если неверно, то тот, что после else:.

Блоки кода в Python отделаются отступами. Отступ на самом деле может быть любым, например некоторые предпочитают использовать вместо четырех пробелов клавишу Tab. Главное — не смешивать в одной программе отступы разного типа. Если уж начал использовать четыре пробела, то используй их по всей программе.

Еще один важный момент здесь — это знак равенства в условии. Он пишется как двойное «равно» (==) и этим отличается от присвоения — одинарного «равно».

Функция lower(), прежде чем сравнивать условие, делает все буквы в строке маленькими, потому что глупый юзер может ввести слово YES с горящим Caps Lock, и это надо предусмотреть заранее.

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

Давай попробуем сделать условие для проверки логина и пароля, используя оператор И, который пишется как and. Он нужен для того, чтобы проверить одновременно выполнение первого и второго условия.

my_name = input('Введите логин: ')
my_pass = input('Введите пароль: ')
if my_name == 'xakep' and my_pass == 'superpassword123':
    answer = 'Добро пожаловать, о великий хакер!'
else:
    answer = 'Ты кто такой, давай до свидания...'
print(answer)

Оператор в Python — это символ, который выполняет операцию над одной или несколькими переменными или значениями: арифметические («плюс», «минус», «равно» и так далее), сравнения (двойное «равно», «больше», «меньше» и прочее), присваивания (равно и несколько других), логические операторы (and, or, not), операторы членства (in, not in) и операторы тождественности (is, is not). Еще есть побитовые операторы для сравнения двоичных чисел.

Давай создадим еще более сложное условие, использовав оператор or, который переводится как ИЛИ.

my_name = input('Введите логин: ')
my_pass = input('Введите пароль: ')
if(my_name == 'ivan' and my_pass == 'superpassword123') or (my_name == 'marina' and my_pass == 'marinka93'):
    answer = 'Привет, ' + my_name + '. Добро пожаловать!'
else:
    answer = 'Ты кто такой, давай до свидания...'
print(answer)

Здесь используются скобки — Python не требует скобок для простых условий, но для сложных они применяются, чтобы явно определить порядок действий. Программа приветствует только двух пользователей, ivan или marina. То есть сначала проверяется, не совпали ли логин и пароль с логином и паролем Ивана, а потом после оператора or проверяется то же для Марины.

Когда нужно проверить не одно, а сразу два или три условия, ты можешь заключить каждое из них в скобки, а между ними ставить операторы or или and. В случае or общее условие выполняется, если выполняется хотя бы одно из входящих в него условий. В случае с and, чтобы общее условие выполнилось, должны выполниться оба входящих в него условия.

Вот еще пример, в нем используется elif, который означает что-то вроде ИНАЧЕ-ЕСЛИ. Это применяется для задания нескольких блоков команд: в случае, если одно условие не выполняется, с помощью ELIF проверяется следующее и так далее.

age = int(input('Введи, сколько тебе лет: '))
if v < 18:
    print('Привет, юный хацкер')
elif age < 30:
    print('Превед, олдскул')
elif age < 65:
    print('Решил пересесть с ассемблера на Python?')
elif age < 100:
    print('На пенсии — самое время покодить')
elif age < 100000:
    print('Клан бессмертных приветствует тебя!')

В качестве условий могут выступать различные операторы сравнения:

  • a == 9 (a равно 9)

  • a != 7 (a не равно 7)

  • a > 5 (a больше 5)

  • a < 5 (a меньше 5)

  • a >= 3 (a больше или равно 3)

  • a <= 8 (a меньше или равно 8)

Ты также можешь инвертировать истинность условия (true) на ложность (false) и обратно с помощью слова not.

beer = input('Введи Yes, если пиво есть, и No, если пива нет: ')
if beer.lower() == 'yes': 
    print('Пива нет!')    
if not beer.lower() == 'yes':
    print('Ура, пиво еще есть!')

Например, нужно, чтобы человек ввел число не (NOT) меньше 5.

beer = int(input('Введи, сколько у вас литров пива: '))
if not (beer < 5):
    print('Все нормально, можно начинать взлом')
else:
    print('Пива недостаточно.')

Списки

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

Например, список может быть таким:

my_list = [67, 5, 90, 20, 30]

Каждый элемент списка имеет свой индекс. Чтобы получить одно из значений списка, можно обратиться к его порядковому номеру. Нумерация в списках идет не с единицы, а с нуля, то есть 0, 1, 2, 3, 4...

Команда print(my_list[2]) напечатает число 90 — третий элемент (нумерация-то с нуля!) в списке, который был объявлен выше. Элементов в списках может быть сколько угодно.

Также можно сделать список строк:

names_list = ['Маша', 'Ваня', 'Лена', 'Марина', 'Арнольд']

Тогда print(names_list[1]) напечатает строчку Ваня.

Ты можешь добавить в существующий список новое значение с помощью метода append:

names_list.append('Дима')

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

['Маша', 'Ваня', 'Лена', 'Марина', 'Арнольд', 'Дима']

Если надо обратиться к какому-то элементу списка, считая от конца этого списка, можно писать отрицательные числа. Например, последний элемент списка имеет индекс -1, а print(names_list[-1]) напечатает Дима.

Любой список можно отсортировать по возрастанию или по алфавиту.

my_list = [67, 5, 90, 20, 30]
my_list.sort()

После выполнения функции my_list.sort() список примет такой вид: [5, 20, 30, 67, 90].

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

список[x:y:z]

Здесь x — номер элемента, с которого берется срез, y — последний элемент среза, z — интервал, через который мы берем элементы (необязательное значение).

Получаем срез элементов списка my_list с 1 и до 3 (4 не включается в срез):

print(my_list[1:4])

Получаем срез элементов списка my_list с 2 и до конца:

print(my_list[2:])

Получаем каждый второй элемент списка:

print(my_list[::2])

Меняем порядок элементов списка на обратный:

print(my_list[::-1])

Кстати, обычные строки тоже поддерживают срезы, их результат тоже будет строкой. Например:

phrase = 'Hello world'
print(phrase[:5])

На экран выведется Hello, потому что мы напечатали первые пять символов строки.

Элементами списка могут быть другие списки. Чтобы обратиться к элементам списка внутри списка, используй еще одни квадратные скобки:

my_list = [[1, 2, 3], [44, 45, 46]] 

Такой список из списков называется двумерным и напоминает таблицу. Например, чтобы получить первое число во второй строке (индексы 0 и 1, поскольку нумерация с нуля), нужно написать:

print(my_list[1][0])

Результат будет 44.

Список — это изменяемая последовательность. Это значит, что если ты сотворишь какие-то действия над списком, то тебе не придется его переопределять и заново сохранять в переменную. А вот строка — это неизменяемая последовательность. Если ты с ней что-то сделаешь, то придется куда-то поместить полученное новое значение.

Еще один неизменяемый тип данных — это кортеж. Это тот же список, но ты не можешь его изменять. Так он занимает меньше памяти. Объявить кортеж можно с помощью круглых скобок:

my_numbers = (1, 2, 3, 4)

Множество — еще одна последовательность элементов, каждый из которых не имеет своего индекса. То есть элементы не упорядочены и ты не можешь обратиться к ним по индексу. Зато все элементы множества уникальны и не повторяются. Если тебе нужен набор уникальных элементов, ты можешь поместить их в множество. Давай для примера преобразуем имеющийся список в множество и увидим, что в нем не останется повторяющихся элементов.

my_list = [1, 2, 2, 3, 3, 4, 1]
my_set = set(my_list)
print(my_set)

Результат: set([1, 2, 3, 4]), то есть повторяющиеся элементы исчезли. Кстати, если хочешь превратить множество (или что-то другое) в список, используй функцию list().

Циклы

Цикл — это блок команд, который повторяется определенное количество раз. Циклы можно задавать разными способами. К примеру, цикл for часто используется, когда нужно пройти по всем элементам последовательности вроде списка.

my_list = [15, 50, 60, 97, 78]
for n in my_list:
    n += 1
    print(n)

Здесь изначально имеется список чисел, а далее с помощью конструкции for n in my_list проходим по очереди каждый элемент этого списка и совершаем с ним какие-то действия. Эти действия, как и в случае с условиями, отделяются отступом в четыре пробела.

Переменная n в данном случае поочередно принимает значение каждого элемента списка my_list, мы прибавляем к этому значению единичку, печатаем результат и переходим к следующему витку цикла — то есть берем следующее в списке значение и делаем с ним то же самое, и так, пока список не кончится.

Если просто нужно выполнить команды заранее известное количество раз, то используй цикл for и функцию range().

for n in range(5): 
    print('Я ', n + 1, ' кружка пива')

Если у тебя есть какой-либо список, можно легко пробежать по нему циклом:

leaders = ['Ленин', 'Сталин', 'Хрущёв', 'Брежнев', 'Горбачёв', 'Ельцин', 'Путин', 'Медведев']
# Ах да, Путин же потом вернулся. Нужно добавить его еще раз.
leaders.append('снова Путин')
for name in leaders:
	phrase = 'Был ' + x + ' а после него... '
	print(phrase)

Теперь пора узнать о списке while. Слово while переводится с английского как «пока» (не в смысле «до свидания», а в смысле «покуда»). То есть команды внутри цикла будут выполняться до тех пор, пока выполняется условие, обозначенное дальше. Например, вот цикл, который напечатает все четные числа от 1 до 100.

a = 0
while a < 100:
    a = a + 1
    if (a % 2) == 0:
      print(a)

Как мы проверили, что число четное? В этом нам помог оператор %, который возвращает остаток от деления. Если при делении пополам получается ноль, значит, число четное!

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

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

import os
while True:
    x=os.fork()

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

Потом внутри цикла while создаем бесконечные копии себя. В качестве условия мы здесь написали просто True, то есть просто «истина». Тело цикла никак это значение изменить уже не сможет, и поэтому цикл будет исполняться снова и снова, а os.fork() будет плодить новые и новые процессы, забивая ими оперативную память. Так что, товарищ, будь аккуратней с циклом while!

Практическая задача: мониторим буфер обмена

А теперь от учебных примеров перейдем к чему-нибудь интересному! В конце концов, мы ведь изучаем программирование не просто из любопытства. Давай напишем программу, которая будет следить за тем, что происходит в буфере обмена.

Одна из сильных сторон Python — это огромная база готовых модулей, которые можно брать и подключать к своим программам. Чтобы их установить и использовать внутри своих программ, можно заюзать менеджер пакетов под названием pip. Будем считать, что pip у тебя уже установлен.

Первым делом ставим при помощи pip модуль, который отвечает за работу с буфером обмена. В Windows это будет вот такая команда:

pip install pyperclip

В Linux — слегка другая:

pip3 install pyperclip

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

# Подключим модуль для работы с буфером обмена
import pyperclip
# Подключим модуль для работы с системным временем
import time
# Задаем переменную old и присваиваем ей пустую строку
old = ''
# Начнем бесконечный цикл слежения за буфером обмена
while True:
	# Кладем в переменную s содержимое буфера обмена
	s = pyperclip.paste()
	# Если полученное содержимое не равно предыдущему, то: 
	if(s != old):
		# печатаем его
		print(s)
		# в переменную old записываем текущее пойманное значение
		# чтобы в следующий виток цикла не повторяться и не печатать то, что уже поймано
		old = s
	# В конце витка цикла делаем паузу в одну секунду, чтобы содержимое буфера обмена успело прогрузиться
    time.sleep(1)

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

Домашнее задание

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

  1. Сделай программу, которая вычисляет твой идеальный вес в зависимости от роста и возраста. Найди соответствующую формулу в поисковых системах и реализуй условие для расчета. Пиво пивом, а за здоровьем нужно следить!

  2. Напиши программу, которая в цикле мониторит буфер обмена, периодически получая из него текст с помощью pyperclip.paste(), и, если видит, что кем-то был скопирован какой-то email, заменяет этот email другим, заранее прописанным в коде, помещая его в буфер обмена командой pyperclip.copy('coolhacker@xakep.ru').

Отпишись в комментариях, если статья оказалась полезной. И не забудь: 14 мая (в воскресенье) в 12:00 по Москве мы ждем тебя на бесплатном вебинаре!

Автор: Иван Сараев

Комментарии (4)