Учебник по информатике. Программирование на Python. Основы 1 Программирование на Python. Основы
Скачать 1.27 Mb.
|
Открытый учебник по информатике. Программирование на Python. Основы 1 Программирование на Python. Основы Переменные и условный оператор Детальное изучение организации памяти и переменных в языке программирования (точнее при интерпретировании или компилировании программного кода) очень важный момент для тех, кто хочет научиться пользоваться отдельным языком на высоком уровне. Поэтому в этой главе мы разберемся с тем, как в Python устроена модель хранения данных и какие простые типы поддерживаются, изучим базовые операции работы с числами и первые управляющие конструкции. Далее рассматривается реализация CPython, считающаяся эталонной реализацией. Также есть и другие: Jython, IronPython, PyPy, Stackless Python. Типы данных Перед тем, как данные обрабатывать с помощью программы хорошо бы выяснить, с какими типами данных Python вообще умеет работать. И базовых типов данных оказывается достаточно много: Название типа Что хранит None Неопределенное значение bool Логическое значение (истина/ложь) – True/False int Целое число float Вещественное число complex Комплексное число list Список значений tuple Кортеж (аналогия: неизменяемый список) range Диапазон str Строка bytes Неизменяемый набор байт (аналогия: кортеж байт) bytearray Набор байт (аналогия: список байт) memoryview Тип для работы с буфером обмена set Множество frozenset Неизменяемое множество dict Словарь Типы данных, такие как complex, bytes, bytearray и memoryview, в данном учебнике рассматривать не будем ввиду экзотичности их использования. Это не значит, что они не нужны. Учебник по базовым понятиям и структурам, эти Открытый учебник по информатике. Программирование на Python. Основы 2 же типы данных предназначены для решения определенных классов задач, которые в рамках данного учебника рассматриваться не будут. Типы данных можно условно разделить на изменяемые и неизменяемые. Понимание к какому классу принадлежит тот или иной тип очень важно при работе с изменяющимися значениями. Неизменяемые типы данных Изменяемые типы данных bool list int set float dict tuple str frozenset range Ничего странного в том, что привычные типы являются неизменяемыми. Дело в том, что такие объекты при попытке изменения значения не изменяются, вместо этого создается новый объект с новым значением. Представление данных в памяти Любые значения – сохраняемые для дальнейших действий или нет – перед использованием необходимо добавить в память. Перед этим Python каждое значение преобразует в объект PyObject. Чтобы не погружаться в дебри организации структуры данных в памяти, будем рассматривать PyObject как совокупность трех значений– тип данных (type), значение (value), количество ссылок на объект (refcount). Последнее значение указывает на количество ссылающихся на объект переменных. Даже если мы хотим сделать что-то очень простое, происходит именно так. Например, чтобы вывести на экран сообщение «Hello, world!» запишем следующий код. Для его выполнения CPython сначала создаст объект с типом str, значением «Hello, world!» и количеством ссылок равным 0. Рисунок 1. Пример объекта как PyObject Все операторы и функции работают именно с представлениями в виде PyObject, поэтому очень полезно держать этот момент в голове. Открытый учебник по информатике. Программирование на Python. Основы 3 Переменные и оператор присваивания Исторически сложилось, что программа на любом языке программирования описывает последовательность вычислений. Причем эта последовательность может выполняться исходя из весьма сложной логики, которая описывается с помощью управляющих конструкций и структур языка программирования. Это может быть как хрестоматийная программа для вычисления корней квадратного уравнения, так и программа для управления автопилотом автомобиля. В любой из них производится последовательность вычислений, приводящая к результату – корни уравнения или поворот колес и изменение скорости. Да, иногда вычисления происходят не всегда в понятной человеку последовательности, однако вычисления остаются таковыми в любом случае. При описании сложных последовательностей вычислительных преобразований возникает необходимость сохранять промежуточные вычисления. Для этого используют переменные. Переменная представляет собой последовательность символов – имя – по которой можно обратиться к значению, хранящемуся в памяти. Имя переменной составляется по следующим правилам: - первый символ является буквой или знаком нижнего подчеркивания, - второй и последующий символы – буквы, цифры или знаки подчеркивания. Принято использовать «змеиный стиль» [1], то есть составные имена представлять как набор слов, разделенных знаком подчеркивания, например, long_long_name. Открытый учебник по информатике. Программирование на Python. Основы 4 Оператор присваивания Для определения объекта, на который будет ссылаться переменная, используется оператор присваивания. имя_переменной = выражение Для этого необходимо слева от оператора присваивания определить имя переменной, значение которой мы определяем, справа – записать выражение, которое вычисляет сохраняемое значение. Также в Python 3.8 был добавлен оператор присваивания, возвращающий значение, так называемый «моржовый оператор» (walrus operator). имя_переменной := выражение Так стало возможно записывать некоторые последовательности вычислений компактнее и использовать значения, вычисленные при проверке условий, без повторного вычисления. Пример. x = (y := 10)**2 В результате работы такой конструкции переменная y будет ссылаться на значение 10, переменная х – на 100. ВАЖНО. В большинстве случаев выражение, содержащее моржовый оператор, необходимо записывать в скобках. Так, следующая запись будет синтаксически неверна: y := 10 В то время, как запись ниже будет правильной альтернативой варианту выше. (y := 10) Открытый учебник по информатике. Программирование на Python. Основы 5 Объект в памяти Как же выглядит переменная в памяти? Что она хранит? И насколько вообще корректно в Python называть переменную переменной? Последний вопрос больше философский, однако с позиции терминологии очень важный. Разберемся с ним в конце данного параграфа. Простой пример (числа слева – номера строк). 1. x = 500 2. y = 300 3. x = x – 200 Что же происходит в памяти? В первую очередь определяются типы объектов в выражении справа и вычисляется значение. Для первых двух строк получится, что сначала инициализируется объект (целое число 5 для х, целое число 3 для y). Затем имя переменной сопоставится с адресом объекта. Рисунок 2. Присваивание числовых значений переменным На этом моменте очень важно вспомнить, что int – неизменяемый тип данных, то есть при изменении значения в ходе вычислений мы получаем ссылку на другой объект с новым значением. Исследуем данный нюанс на примере строки 3 нашей программы. Открытый учебник по информатике. Программирование на Python. Основы 6 Первый этап – вычисление выражения. Рисунок 3. Вычисление выражения x – 200 Так как уже есть неизменяемый объект с таким значением – объект соответствующий y – для x создается соответствие с этим же объектом. Рисунок 4. Сопоставление имени x объекту для значения 3 Также можно заметить, что для объекта числа 500 количество ссылок стало равно 0, для числа 300 – 2. Поэтому объект для числа 500 будет удален, чтобы не расходовать память на неиспользуемое значение. Эта операция связана с процедурой оптимизации используемой памяти. В рамках данной главы мы не будем подробно рассматривать такие алгоритмы. Подробнее с данным материалом можно ознакомиться в источнике [2]. Открытый учебник по информатике. Программирование на Python. Основы 7 Так что же такое переменная? И переменная ли? На самом деле в Python термин «переменная» скорее пришел из других языков программирования. И в Python переменной называется имя связанное с объектом. Это можно наблюдать в разобранном выше примере, где существует две переменные, которые ссылаются на один и тот же объект в памяти! В реализациях таких языков программирования, как Pascal или C, для каждой переменной создается отдельный объект, который не изменяет (без нашего вмешательства) своего адреса и содержит необходимые данные (даже если они одинаковые для разных переменных). В Python же мы имеем дело с именованием объектов, которые существуют в памяти независимо от «переменных». Преобразование типов Еще одной интересной особенностью Python является динамическая типизация – такой принцип определения типа объекта, когда тип определяется исходя из результата выражения и используемых в нем значений. s = '2134' # str s = 1234 # int s = 1234.4321 # float s = True # bool Здесь же стоит отметить, что язык Python является строгим динамически типизированным языком. Это означает, что если в выражении мы используем неявно определенные операции, например сложение строки и числа, то вычисление такого выражения вернет ошибку. s = '2134' + '123' # str + str = str s = 1234 + 12 # int + int = int s = 1234.4321 + 12.21 # float + float = float s = 1234.4321 + 12 # float + int = float s = True + True # bool + bool = int s = '123' + 12 # error Открытый учебник по информатике. Программирование на Python. Основы 8 Если необходимо преобразовать значение переменной из одного типа в другой используют функции для преобразования типов. Функция Преобразуемый тип Комментарий bool Любой Нулевое значение – False Ненулевое – True bool(0) == False float int, float, complex, str Строка преобразуется только в случае соответствия формату числа int int, float, complex, str При преобразовании строки можно указать систему счисления. Строка будет преобразована только если соответствует числовому представлению. Для числовых типов функция int выделяет целую часть. str Любой Теперь мы можем переписать ошибочное выражение, определив последовательность преобразований. s = '123' + str(12) # '12312' str + str = str s = int('123') + 12 # 135 int + int = int Открытый учебник по информатике. Программирование на Python. Основы 9 Перевод строки в целое число По умолчанию преобразование строкового значения в целое число происходит в десятичную систему счисления. >>> int('10232') 10232 Однако, можно преобразовывать строковые значения чисел, которые представлены и в других системах счисления. Для этого необходимо в качестве второго аргумента указать основание системы счисления – int(s, b). Здесь s – строковое представление числа в b-ричной системе счисления. Цифры после 10 – символы английского алфавита a-z в любом регистре. Поддерживается перевод чисел из систем счисления с основаниями от 2 до 36. Пример: x = int('1A20', 13) # x = 1A20(13)= 3913(10) Также существует возможность обратного перевода в системы счисления с основаниями 2, 8, 16 через форматированные строки или встроенные функции bin, oct, hex. Основание Запись (f-строки) Запись (функции) 2 f'{x:b}' bin(x) 8 f'{x:o}' oct(x) 16 f'{x:x}' hex(x) Заметим, что тип результата – строка. Также отметим, что встроенные функции в начале строки возвращают префикс – 0b, 0o и 0x для 2, 8 и 16 систем счисления соответственно. Примеры. Перевести число 223 в строковое двоичное представление. f-строка Функции >>> f'{223:b}' '11011111' >>> bin(223) '0b11011111' Перевести значение переменной var (1443) в строковое шестнадцатеричное представление. f-строка Функции >>> f'{var:x}' '5a3' >>> hex(var) '0x5a3' Открытый учебник по информатике. Программирование на Python. Основы 10 ВАЖНО №1: с помощью форматирования нельзя перевести в любую систему счисления. Для этого используют специальные алгоритмы, которые мы рассмотрим в будущем. ВАЖНО №2: при работе с f-строками и переводом в 2, 8, 16 системы счисления используются СИМВОЛЫ (b, o, x), обозначающие основание системы счисления. Подробнее о f-строках поговорим в дальнейших главах. Множественное присваивание В данном параграфе множественное присваивание рассмотрим в более узком понятии, чем оно есть. Другие особенности данного механизма будем вводить постепенно в последующих главах. На данном этапе для нас важно, как минимизировать код или сделать его более читаемым. Python синтактически поддерживает возможность задавать значения нескольких переменных с помощью одного оператора присваивания. Для этого слева от оператора присваивания надо указать все имена переменных, которые мы хотим изменить/инициализировать, справа – соответствующее количеству переменных слева количество значений. a, b = 1000, 450 + 550 Интересный факт! При запуске такого кода в оболочке REPL оба имени a и b будут ссылать на один объект. Также существует альтернативный способ задать для нескольких переменных один и тот же объект. a = b = 1000 В таком случае создается один объект со значением 1000 и адрес объекта записывается в переменные a и b. Открытый учебник по информатике. Программирование на Python. Основы 11 Операции Для обработки и преобразования данных нужно определиться, какие операции есть в нашем распоряжении. В данном параграфе рассмотрим базовые арифметические и логические операции, а также приоритет их выполнения. Арифметические операции Результатом арифметической операции является число. Надо отметить, что в арифметическом выражении могут участвовать и данные логического типа. В таком случае True интерпретируется как 1, False – как 0. Операция Обозначение Пример использования Унарный минус - -10 Сложение + 2 + 2 # 4 False + 3 # 3 Вычитание - 10 – 18 # -8 True – 5 # -4 Умножение * 4*5 # 20 Деление / 10 / 4 # 2.5 Возведение в степень ** 2**4 # 16 Целочисленное деление // 10 // 2 # 5 13 // 5 # 2 -12 // 7 # -2 13 // -6 # -3 -10 // -3 # 3 10 // 2.6 # 3.0 Остаток от деления % 10 % 2 # 0 13 % 5 # 3 -12 % 7 # 2 13 % -6 # -5 -10 % -3 # -1 10 % 2.6 # 2.2 Взятие модуля Абсолютное значение abs(x) abs(-10) # 10 abs(1000) # 1000 Операция «унарный минус» делает из числа (подвыражения) в начале выражения отрицательное значение. Так при записи -10 + 20 сначала выполнится операция унарного минуса «-10» и только затем произойдет сложение «-10» и «20». Открытый учебник по информатике. Программирование на Python. Основы 12 Функции целочисленного деления и нахождения остатка от деления работают по следующему правилу: если число a не делится нацело на b, то знак остатка должен совпадать со знаком делителя. Или соблюдается одно из следующих условий. [ 0 ≤ 𝑟 < 𝑏 𝑏 < 𝑟 ≤ 0 , где b – делитель, r – остаток. Результат целочисленного деления в таком случае можно представить, как 𝑎//𝑏 = ⌊ 𝑎 𝑏 ⌋ , где ⌊𝐴⌋ − округление вниз (до меньшего или равного целого). Соответственно, 𝑎%𝑏 = 𝑎 − (𝑎//𝑏) ∙ 𝑏 Поэтому −12//7 = ⌊ −12 7 ⌋ = ⌊−1 5 7 ⌋ = −2 −12%7 = −12 − (−12//7) ∙ 7 = −12 − (−2) ∙ 7 = −12 + 2 ∙ 7 = 2 Или 13//(−6) = ⌊ 13 −6 ⌋ = ⌊−2 1 6 ⌋ = −3 13%(−6) = 13 − 13%(−6) ∙ 7 = 13 − (−3) ∙ (−6) = 13 − 18 = −5 Также данные операции могут быть применены к вещественным числам. Логика вычисления остается такая же – результат целочисленного деления является вещественным числом с нулевой дробной частью, результат для остатка от деления вычисляется по приведенной выше формуле. Существует и другой подход к работе с остатками, когда остаток не может быть отрицательным. Например, остаток от деления 13 на -6 будет равен 1, а сам результат целочисленного деления равен 2. При этом формула 𝑎 = 𝑏 ∙ 𝑟 + 𝑞 где b – делитель, r – результат целочисленного деления, q – остаток, справедлива для обоих случаев (Python и данного определения). Открытый учебник по информатике. Программирование на Python. Основы 13 Знаки сравнения Для числовых данных. Операция Обозначение Пример использования Равно == 4+2 == 3+3 # True False == True # False Не равно != 3+1 != 2+2 # False Больше > 2 > 2 – 3 # True Больше или равно >= 2 >= 1+1 # True Меньше < 3 < 10 # True Меньше или равно <= 5 <= 1 # False True <= False # False При использовании операторов присваивания с логическими значениями, последние сначала преобразуются в числовое представление – True в 1, False в 0. Посмотрим, какие значения получаются в таком случае. A B == != > >= < <= False False 1 0 0 1 0 1 False True 0 1 0 0 1 1 True False 0 1 1 1 0 0 True True 1 0 0 1 0 1 Также в Python есть механизм цепочек сравнения (chaining comparison operators) с помощью которого, в числе прочего, удобно обозначать диапазоны значений числовых переменных. Пример. Число х в диапазоне [10; 110]. 10 <= x <= 110 Про сравнение объектов других типов будет рассказано в следующих главах. Открытый учебник по информатике. Программирование на Python. Основы 14 Логические операции Логические операции применяются для связки логических выражений. |