3.1. Теория

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

3.1.1. Понятие типа данных и переменной

Тип данных (англ. Data type) - характеристика, определяющая:

  • множество допустимых значений, которые могут принимать данные, принадлежащие к этому типу (например, объект типа Целое число может принимать только целочисленные значения в определенном диапазоне);

  • набор операций, которые можно осуществлять над данными, принадлежащими к этому типу (например, объекты типа Целое число умеют складываться, умножаться и т.д.).

Все типы в Python являются объектами (в отличие, например, от C++). При создании объекта вызывается специальная функция - конструктор.

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

Примечание

PEP8.

Для имен переменных используется змеиный_регистр (англ. snake_case): например, my_variable или i.

Примечание

Информативные имена переменных.

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

Например, переменную, хранящую данные о скорости можно назвать speed, а не sk; значение баланса телефона клиента - balance, а не b и т.д. «Привычные» со школы короткие имена следует использовать там, где они либо подходят по смыслу (например, a, b, c в роли коэффициентов квадратного уравнения), либо используются временно (например, счетчик i в циклической конструкции).

3.1.1.1. Классификация типов данных

В Python встроенные типы данных подразделяются на 2 группы:

  1. Скалярные (неделимые).

    1. Числа (целое, вещественное).

    2. Логический тип.

    3. NoneType.

  2. Структурированные (составные) / коллекции.

    1. Последовательности: строка, список, кортеж, числовой диапазон.

    2. Множества.

    3. Отображения: словарь.

Кроме того, все объекты в Python относятся к одной из 2-х категорий:

  1. Мутирующие (англ. Mutable): содержимое объекта можно изменить после создания (например, список);

  2. Немутирующие (англ. Immutable): содержимое объекта нельзя изменить после создания (например, строка или число).

Также часто используется терминология «изменяемые» и «неизменяемые» типы соответственно.

Как мутирующие, так и немутирующие объекты имеют свои преимущества и недостатки. Основным преимуществом немутирующих типов является гарантия неизменяемости с момента создания: каждый использующий участок кода имеет дело с копией объекта и не может его каким-либо образом изменить. Этот же принцип формирует основной недостаток немутирующих типов: большее количество потребляемой памяти на дополнительное копирование объектов при необходимости внесения изменений.

3.1.1.2. Оператор присваивания

Для связывания (и при необходимости предварительного создания) объекта и переменной используется оператор присваивания =.

Присваивание выполняется «справа налево» и подразумевает шаги:

  • если справа от оператора находится литерал (например, строка или число) в операнд слева записывается ссылка, которая указывает на объект в памяти, хранящий значение литерала:

    a = 100  # Создание объекта 100 и запись ссылки на него в переменную 'a'
    
  • если справа находится ссылка на объект, в левый операнд записывается ссылка, указывающая на тот же самый объект, на который ссылается правый операнд;

    a = 100
    b = a  # В переменную 'b' копируется ссылка из 'a' -
           # они будут указывать на один и тот же объект
    

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

В связи с этим целесообразнее в Python в качестве метафоры рассматривать переменные как стикеры (этикетки), цепляемые к данным, а не ящики (Рисунок 3.1.1) и говорить, что «переменная присвоена объекту», а не привычное «переменной присвоен объект».

_images/03_01_01.png

Рисунок 3.1.1 - Переменные в Python - стикеры, а не ящики 3

Пример использования оператора присваивания приведен в Листинге 3.1.1.

Листинг 3.1.1 - Оператор присваивания в Python
# Выражение присваивания в Python может быть записано несколькими способами в
# зависимости от содержимого левой части (l-значение) и правой части (r-значение).

# 1. Простое присваивание использует одно l-значение и одно r-значение.
#
# Объект 5 целого типа связывается с переменной 'a'
>>> a = 5
>>> a
5

# 2. Сокращенная запись присваивания часто применяется когда нужно обновить
#    значение переменной по отношению к текущему значению.
#    Сокращенная запись образуется для всех операторов одинаково, например
#    '*=' для умножения и т.д.
#
# Увеличиваем значение связанного целого объекта 'a' на 1, эквивалентно a = a + 1
>>> a += 1
>>> a
6

# 3. Также возможно параллельное присваивание, где выражение присваивания
#    содержит больше одного l- и r-значений.
#
# Связывание значений 1, "aaa", 3 с переменными 'x', 'y', 'z' соответственно
>>> x, y, z = 1, "aaa", 3
>>> x, y, z
(1, 'aaa', 3)

# Возможно также не совпадения количества значения l- и r-значений,
# данный случай рекомендуется рассмотреть самостоятельно.

# 4. Оператор присваивание выполняется справа налево, поэтому также можно
#    образовывать цепочки присваивания.
#
# 0 связывается с переменной 'y', а затем и с переменной 'x'
>>> x = y = 0
>>> x, y
(0, 0)

Примечание

Инициализация переменной перед использованием

Переменная должна быть проинициализирована (ссылаться на данные) перед использованием в выражении. Например, код a = b + 2 или b += 1, вызовет ошибку, если идентификатор b не был предварительно определен.

Примечание

Присваивание и побочный эффект

Присваивание, меняя значение переменной, изменяет состояние программы - т.е. имеет побочный эффект. После выполнения присваивания, например x += 1, весь дальнейший код программы будет иметь дело с новым, измененным значением 1.

3.1.1.3. Управление памятью и сборщик мусора

Создание объекта любого типа подразумевает выделение памяти для размещения данных об этом объекте. Когда объект больше не нужен - его необходимо удалить, очистив занимаемую память. Python - язык с встроенным менеджером управления памятью и выполняет данные операции автоматически за счет наличия сборщика мусора (англ. Garbage Collection, GC).

Сборка мусора - технология, позволяющая, с одной стороны, упростить программирование, избавив программиста от необходимости вручную удалять объекты, созданные в динамической памяти, с другой - устранить ошибки, вызванные неправильным ручным управлением памятью. Алгоритм, используемый сборщиком мусора называется подсчетом ссылок (англ. Reference Counting). Python хранит журнал ссылок на каждый объект и автоматически уничтожает объект, как только на него больше нет ссылок (Рисунок 3.1.2).

_images/03_01_02.gif

Рисунок 3.1.2 - Примерная схема работы сборщика мусора

Время между созданием и уничтожением объекта - его жизненный цикл.

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

3.1.2. Скалярные типы

3.1.2.1. Числа

В Python существует 2 категории чисел: целые и вещественные (с плавающей точкой).

3.1.2.1.1. Целое число

Целые числа в Python представлены типом int.

class int(x=0)
class int(x, base=10)

Конструктор класса int.

Размер целого числа ограничивается только объемом памяти компьютера. Литералы целых чисел по умолчанию записываются в десятичной системе счисления, но при желании можно использовать и другие (Листинг 3.1.2).

Листинг 3.1.2 - Пример литералов целых чисел
>>> 15      # десятичное число
15

>>> 0b1111  # двоичное число
15

>>> 0o17    # восьмеричное число
15

>>> 0xF     # шестнадцатиричное число
15

3.1.2.1.2. Вещественное число

Python предоставляет три типа значений с плавающей точкой:

  • float (двойная точность)

  • complex (комплексные числа вида 3.5 + 5j);

  • decimal.Decimal (большая точность, по умолчанию 28 знаков после запятой).

class float([x])

Конструктор класса float.

Наиболее часто используемый тип float представляет числа с плавающей точкой двойной точности, диапазон значений которых зависит от компилятора, применявшегося для компиляции интерпретатора Python. Числа типа float записываются с десятичной точкой или в экспоненциальной форме записи (Листинг 3.1.3).

Листинг 3.1.3 - Пример литералов вещественных чисел
>>> 5.7              # Точка - разделитель целой и дробной части
5.7

>>> 4.               # Если дробной части нет, ее можно опустить
4.0

>>> -2.5             # Отрицательное вещественное число
-2.5

>>> 8e-4             # Экспоненциальная форма записи
0.0008

>>> 0.1 + 0.2        # Проблема потери точности актуальна для вещественных чисел
0.30000000000000004

Для чисел с плавающей точкой существует ряд нюансов:

  • в машинном представлении такие хранятся как двоичные числа. Это означает, что одни дробные значения могут быть представлены точно (такие как 0.5), а другие - только приблизительно (такие как 0.1 и 0.2, например, их сумма будет равна не 0.3, а 0.30000000000000004);

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

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

3.1.2.1.3. Операции над числами

Типовые операции, которые можно производить над числами (int и float), указаны в Листинге 3.1.4.

Для арифметических операций тип результата операции определяется типом аргументов. Если тип результата явно не предусмотрен при вычислении (например, округление до целых подразумевает получение результата типа int), действуют следующие правила:

  • float: если хотя бы один аргумент имеет тип float;

  • int: если все аргументы имеют тип int.

Листинг 3.1.4 - Операции над числами в Python
# 1. Арифметические операции
#    Тип результата операции определяется типом аргументов

# -х
# Меняет знак х на обратный
>>> x = 5
>>> -x
-5

# х + у, х - у, х * у
# Сложение, разность, произведение чисел х и у
>>> 5 + 3
8
>>> 5 - 7
-2
>>> 5 * 3
15

# х / у
# Делит х на у (результат типа float)
>>> 5 / 3
1.6666666666666667

# x // y
# Делит х на у нацело - усекает дробную часть (результат типа int)
>>> 5 // 3
1

# х % у
# Возвращает модуль (остаток) от деления х на у
>>> 5 % 3
2

# x**y
# Возводит х в степень у
>>> 5**3
125

# abs(x)
# Возвращает абсолютное значение х
>>> abs(-5)
5

# round(x, n)
# Возвращает значение x, округленное до n знаков после запятой;
# тип результата зависит от n (int, если n равно 0, при этом его можно не указывать)
>>> round(4/3, 2)
1.33
>>> round(4/3)
1

# 2. Равенство и сравнение
#    Результат логического типа

# x == y, x != y
# Проверка чисел на равенство/неравенство
>>> 5 == 4
False
>>> 5 != 4
True

# x > y, x < y, x >= y, x <= y
# Больше, меньше, больше или равно, меньше или равно
>>> 5 > 4
True
>>> 5 <= 5
True

# Возможно составление цепочек сравнений
>>> 3 < 4 <= 5
True

3.1.2.2. Логический тип

Логический тип представлен типом bool:

class bool([x])

Конструктор класса bool.

True
False

и позволяет хранить 2 значения:

  • True (Истина / Да / 1);

  • False (Ложь / Нет / 0).

Операции, которые можно производить над объектами логического типа, указаны в Листинге 3.1.5.

Листинг 3.1.5 - Операции над объектами логического типа в Python
>>> x = True
>>> y = False

>>> not x
False

>>> x and y
False

>>> x or y
True

# Python использует "ленивую" модель вычисления: если на каком-то
# этапе результат выражения известен, оно не вычисляется до конца
>>> (4 > 5) and (5 > 2)
False

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

3.1.2.3. NoneType

None

В Python существует специальное значение None типа NoneType, обозначающее нейтральное или «нулевое» поведение. Присвоение такого значения ничем не отличается от других: a = None, обозначая, что идентификатор a задан, но ни с чем не связан.

Наиболее часто используется для защитного программирования - «если что-то не None, можно продолжать работу программы».

3.1.3. Коллекции

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

Коллекции — это группа типов данных, которые содержат в себе другие данные и поддерживают:

  • проверку на вхождения элементов in и not in (True/False);

  • определение размера len();

  • возможность выполнения итераций (перемещения по элементам последовательности) - из-за этого коллекции также называются итерируемыми объектами (подробнее рассматриваются в Теме №4).

Среди коллекций выделяют 3 группы:

  • последовательности: строка, список, кортеж, числовой диапазон;

  • множества;

  • отображения: словарь.

3.1.3.1. Последовательности

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

Некоторые последовательности в Python в отличие от традиционных массивов (например, в Паскале или Си) могут хранить элементы различного типа (в том числе и коллекции различных видов).

В языке Python имеется пять встроенных типов последовательностей (Таблица 3.1.1).

Далее подробно рассматриваются объекты str, list, tuple и range.

3.1.3.1.1. Общие операции

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

Ниже используются следующие обозначения:

  • s и t: последовательности одного типа;

  • n, k, start, end, step: целые числа;

  • x: произвольный объект, отвечающий критериям соответствующего вызова функции.

Длина
len(s)

Функция len() возвращает длину (количество элементов в последовательности) s.

Конкатенация («склеивание»)
s + t

Возвращает новый объект - «склейку» s и t.

Дублирование
s * n
n * s

Возвращает последовательность, повторяющуюся n раз.

Индексация и срезы

Получить доступ к отдельному элементу или группе элементов последовательности возможно с помощью оператора []. Индексацию (получение отдельного элемента) можно считать частным случаем получения среза (слайсинга).

Оператор получения среза имеет три формы записи:

s[start]
s[start:end]
s[start:end:step]
  • s[start]: индексация (с 0);

  • s[start:end]: срез [start; end);

  • s[start:end:step]: срез [start; end) c шагом step.

В ряде случаев целочисленные параметры start, end и step могут быть опущены. Элемент с индексом end не включается в результат при взятии срезов.

Минимальное и максимальное значения
min(s)
max(s)

Возвращает минимальный и максимальный элементы последовательности s соответственно.

Проверка на вхождение
x in s

Возвращает True, если x входит в последовательность s и False в противном случае.

Индекс (положение) элемента
s.index(x[, start[, end]]) --> int

Возвращает первое вхождение элемента x в последовательность s (между индексами start и end, если они заданы).

Количество повторений
s.count(x)

Возвращает количество вхождений элементов x в последовательность s.

Сортировка
sorted(s, key=None, reverse=False)

Возвращает отсортированный объект в виде списка. Исходный объект при этом не изменяется.

Параметры
  • key – функция сортировки (по умолчанию не учитывается, сортировка осуществляется поэлементно);

  • reverse – если равен True, сортировка осуществляется в обратном порядке.

В Листинге 3.1.6 приведен пример выполнения указанных операций на примере последовательности «Список». Выполнение срезов отдельно рассматривается на примере строк ниже.

Листинг 3.1.6 - Общие операции для последовательностей
>>> s = [1, 2, 3]  # Список из 3-х целых чисел

>>> len(s)
3

>>> 1 in s
True
>>> 5 in s
False

>>> s += [5, 6]
>>> s
[1, 2, 3, 5, 6]

>>> s *= 2
>>> s
[1, 2, 3, 5, 6, 1, 2, 3, 5, 6]

>>> min(s), max(s)
(1, 6)

>>> s.index(5)
3

>>> s.count(4)
0

>>> sorted(s)
[1, 1, 2, 2, 3, 3, 5, 5, 6, 6]

3.1.3.1.2. Строка

Строка (str) - это упорядоченная неизменяемая последовательность символов Юникода.

class str(object='')
class str(object=b'', encoding='utf-8', errors='strict')

Конструктор класса str.

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

Важным для строкового типа является понятие кодировки символов, что в частности, влияет на правила сравнения строк. По умолчанию Python хранит строки в кодировке UTF-8.

Если в строке необходимо использовать специальные символы (например, перенос или одноименные кавычки), можно воспользоваться механизмом экранирования символов, для чего используется специальный символ \. В Таблице 3.1.2 приведены некоторые из экранированных последовательностей.

Таблица 3.1.2 - Экранированные последовательности в Python

Последовательность

Значение

\\

Обратный слеш (\)

\'

Апостроф (')

\"

Кавычка (")

\n

Символ «Перевод строки»

\t

Символ «Табуляция»

Пример создания строковых литералов приведен в Листинге 3.1.7, базовые операции - в Листинге 3.1.8.

Листинг 3.1.7 - Создание строк
# Запись строковых литералов
"Простой текст в кавычках"

'Текст в апострофах'

"""А это текст, который занимает 2 строки
(в данном случае использовать три апострофа не рекомендуется)"""

# Экранированные последовательности начинаются с символа \
"Текст, который содержит \"текст в кавычках\""
'Текст, который содержит \'текст в апострофах\''
"Если внутри кавычки другого типа, можно не 'экранировать'"

"Так в строке будет табуляция\tи\nперенос, а также обратный слеш \\"

# "Отключить" экранирование можно указав, что строка является "сырой"
r"Так в строке не будет табуляция\tи\nпереноса, но будет 2 обратных слеша \\"
Листинг 3.1.8 - Операции над строковым типом
# 1. Арифметические операции
#    Тип результата операции определяется типом аргументов

# s1 + s2
# Соединяет строки s1 и s2
>>> "Py" + "thon"
'Python'
# или просто написать рядом
>>> "Py" "thon"
'Python'

# s1 * n
# Составляет строку из n повторений строки s1
>>> "па" * 2
'папа'

# 2. Равенство и сравнение
#    Результат логического типа
#
#    Операции сравнения выполняются посимвольно слева направо с учетом кодировки.
#    Ознакомиться с таблицей символов Юникода рекомендуется на ресурсе
#    http://unicode-table.com/.

# s1 == s2, s1 != s2
# Проверка строк на равенство/неравенство
>>> "текст1" == "текст2"
False
>>> "текст1" != "текст2"
True

# x > y, x < y, x >= y, x <= y
# Больше, меньше, больше или равно, меньше или равно
>>> "текст1" > "текст2"
False
>>> "текст1" <= "текст2"
True

# Возможно составление цепочек сравнений
>>> "текст1" < "текст12" <= "текст2"
True

# s1 in s2
# Проверка вхождения строки s1 в s2
>>> "p" in "Python"
False

Пример доступа к отдельному символу и получения срезов приведен в Листинге 3.1.9.

Листинг 3.1.9 - Индексация и срезы
# Для индексации и получения срезов удобно пользоваться обозначениями ниже
#
# Индексация
#  +---+---+---+---+---+---+
#  | P | y | t | h | o | n |
#  +---+---+---+---+---+---+
#    0   1   2   3   4   5
#   -6  -5  -4  -3  -2  -1
#
# Срезы
#  +---+---+---+---+---+---+
#  | P | y | t | h | o | n |
#  +---+---+---+---+---+---+
#  0   1   2   3   4   5   6
# -6  -5  -4  -3  -2  -1

>>> s = "Python"

>>> s[0]
'P'
>>> s[3]
'h'

>>> s[-1]  # Последний символ
'n'

>>> s[0:2]  # Срез включает первые 2 символа
'Py'
>>> s[2:-1]  # С 3 по предпоследний символ
'tho'
>>> s[0:-1:2]  # С 1 по предпоследний символ через 2
'Pto'

# Параметры [start] и [end] могут быть опущены
# В таком случае срез берется с начала и до конца строки соответственно
>>> s[:3]  # Первые 3 символа
'Pyt'
>>> s[3:]  # С 3-го символа до конца
'hon'
>>>
3.1.3.1.2.1. Характерные операции

Строки поддерживают все общие операции для последовательностей и имеют ряд дополнительных методов.

chr(i)

Возвращает символ № i из таблицы Unicode.

ord(c)

Возвращает номер символа c из таблицы Unicode.

class str

Пусть s - строка, на которой вызывается метод.

upper()

Возвращает копию строки s в верхнем регистре.

lower()

Возвращает копию строки s в нижнем регистре.

capitalize()

Возвращает копию строки с первым символом в верхнем регистре.

title()

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

count(t[, start[, end]])

Возвращает число вхождений строки t в строку s (или в срез s[start:end]).

find(t[, start[, end]])

Возвращает позицию самого первого (крайнего слева) вхождения подстроки t в строку s (или в срез s[start:end]); если подстрока t не найдена, возвращается -1.

index(t[, start[, end]])

Аналогично str.find(), но генерируется исключение ValueError, если подстрока не найдена.

replace(old, new[, count])

Возвращает копию строки s, в которой каждое (но не более count, если этот аргумент определен) вхождение подстроки old замещается подстрокой new.

split(sep=None, maxsplit=- 1)

Возвращает список строк, разбитых по строке sep.

join(seq)

Возвращает строку-«склейку» элементов seq, используя s в качестве разделителя.

Пример использования строковых методов приведен в Листинге 3.1.10.

Листинг 3.1.10 - Использование строковых методов
>>> s = "ЭТО просТо ТеКст"

>>> ord(s[0])
1069
>>> chr(1069)
'Э'

>>> s.upper(), s.lower(), s.title(), s.capitalize()
('ЭТО ПРОСТО ТЕКСТ', 'это просто текст', 'Это Просто Текст', 'Это просто текст')

>>> s.find("Т")
1

>>> s.replace("Т", "т")
'ЭтО просто теКст'

>>> lst = s.split()
>>> lst
['ЭТО', 'просТо', 'ТеКст']

>>> "-".join(lst)
'ЭТО-просТо-ТеКст'
3.1.3.1.2.2. Форматирование строк

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

class str

Пусть s - строка, на которой вызывается метод.

format(*args, **kwargs)

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

Строка s может содержать фигурные скобки {} (заполнители), указывающие, что их необходимо заменить на какое-либо значение. Заполнитель может содержать индекс или ключевое слово - в противном случае замена будет производится слева направо.

Пример использования метода str.format() приведен в Листинге 3.1.11.

Листинг 3.1.11 - Форматирование строк
>>> age = 20
>>> name = "Максим"

# 1. Без указания индексов подстановки
>>> "Меня зовут {}, мне {} лет.".format(name, age)
'Меня зовут Максим, мне 20 лет.'

# 2. Указание индексов подстановки (их можно и повторять!)
>>> "Меня зовут {0}, мне {1} лет.".format(name, age)
'Меня зовут Максим, мне 20 лет.'

# 3. Именованные аргументы
>>> "{name} ходит на {subject} каждую пятницу".\
... format(subject="Мат. анализ", name="Иван")
'Иван ходит на Мат. анализ каждую пятницу'

# 4. Интерполяция (f-string, начиная с Python 3.6)
>>> f"{name} ходит на {subject} каждую пятницу"
'Иван ходит на Мат. анализ каждую пятницу'

# 5. Модификаторы позволяют дополнительно указывать тип или формат выводимых данных

# 5.1. Вывод вещественного числа с 2-мя знаками после запятой
>>> "За 1 рубль дают ${0:.2f}".format(1/70)
'За 1 рубль дают $0.01'

# 5.2. Или вывод большого числа с "тысячными разделителями"
>>> "Стоимость автомобиля: {:,} руб.".format(5300500)
'Стоимость автомобиля: 5,300,500 руб.'

Примечание

Метод str.format обладает широкими возможностями. Дополнительно ознакомьтесь с официальной документацией по «мини-языку» форматирования.

3.1.3.1.3. Список

Список (list) - это упорядоченная изменяемая последовательность элементов.

Особенности:

  • может содержать элементы разного типа;

  • поддерживает операторы сравнения: при этом сравнивание производится поэлементно (и рекурсивно, при наличии вложенных элементов).

class list([iterable])

Конструктор класса list.

Создать список можно несколькими способами (Листинг 3.1.12).

Листинг 3.1.12 - Создание списка
# 1. Пустой список создается с помощью пустых квадратных скобок или функции list()
>>> []
[]
>>> list()
[]

# 2.  Инициализировать список элементами можно одним из следующих способов:
>>> [1, "text", 2.0]
[1, 'text', 2.0]
>>> list("text")
['t', 'e', 'x', 't']
3.1.3.1.3.1. Характерные операции

Списки поддерживают все общие операции для последовательностей, и имеют ряд дополнительных методов.

class list

Пусть lst - список, на котором вызывается метод.

append(x)

Добавляет элемент x в конец списка lst.

extend(m)
lst += m

Добавляет в конец списка lst все элементы коллекции m.

insert(i, x)

Вставляет элемент х в список lst в позицию i.

remove(x)

Удаляет из списка lst первый элемент со значением x.

pop([i])

Возвращает последний или i-й элемент, удаляя его из последовательности.

clear()

Удаляет из списка lst все элементы (очищает список).

sort(lst, key=None, reverse=None)

Выполняет сортировку списка lst. Отличается от функции sorted() тем, что сортирует исходный объект, а не возвращает новый.

Параметры
  • key – функция сортировки (по умолчанию не учитывается, сортировка осуществляется поэлементно);

  • reverse – если равен True, сортировка осуществляется в обратном порядке.

reverse()

Переворачивает элементы списка lst.

del lst[i[:j]]

Удаляет из списка lst элемент с индексом i (или несколько элементов, если задан индекс j).

В Листинге 3.1.13 приведен пример использования методов списков.

Листинг 3.1.13 - Работа со списками
# 1. Методы списка

>>> a = [8, 7, 5.5, 1000, 3.50, 200]

>>> a[0] = 7
>>> a
[7, 7, 5.5, 1000, 3.50, 200]

>>> a.index(7)
0

>>> a.count(7)
2

>>> a.insert(2, 1000)
>>> a
[7, 7, 1000, 5.5, 1000, 3.5, 200]

>>> a.append(5.5)
>>> a
[7, 7, 1000, 5.5, 1000, 3.5, 200, 5.5]

>>> a += [0, 0]
>>> a
[7, 7, 1000, 5.5, 1000, 3.5, 200, 5.5, 0, 0]

>>> b = a.pop()
>>> b
0
>>> a
[7, 7, 1000, 5.5, 1000, 3.5, 200, 5.5, 0]

>>> a.sort()
>>> a
[0, 3.5, 5.5, 5.5, 7, 7, 200, 1000, 1000]

>>> a.remove(1000)
>>> a
[0, 3.5, 5.5, 5.5, 7, 7, 200, 1000]

>>> del a[2:4]
>>> a
[0, 3.5, 7, 7, 200, 1000]

>>> a.reverse()
>>> a
[1000, 200, 7, 7, 3.5, 0]

# 2. Сравнения и равенство
# Простое сравнение
>>> a = [1, 5, 10]
>>> b = [1, 5, 10]
>>> a == b
True

>>> b[0] = 5
>>> b
[5, 5, 10]
>>> a < b
True

# Вложенное сравнение
>>> a[0] = [3, "aaa"]
>>> b[0] = [3, "bb"]
>>> a, b
([[3, 'aaa'], 5, 10], [[3, 'bb'], 5, 10])
>>> a < b
True

3.1.3.1.4. Кортеж

Кортеж (tuple) - это упорядоченная неизменяемая последовательность элементов.

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

class tuple([iterable])

Конструктор класса tuple.

Создать кортеж можно несколькими способами (Листинге 3.1.14).

Листинг 3.1.14 - Создание кортежа
# 1. Пустой кортеж создается с помощью пустых круглых скобок или функции tuple()
>>> ()
()
>>> tuple()
()

# 2. Инициализировать кортеж элементами можно одним из следующих способов:
>>> 1,
(1,)
>>> 1, 2, "text"
(1, 2, 'text')
>>> s = tuple("text")
>>> s
('t', 'e', 'x', 't')
>>>

# 3. Т.к. структура является неизменяемой, изменение содержимого запрещено
>>> s[0] = "n"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Кортежи поддерживают все операции, общие для последовательностей.

3.1.3.1.5. Числовой диапазон

Числовой диапазон (range) - это упорядоченная неизменяемая последовательность элементов - целых чисел.

class range(stop)
class range(start, stop[, step])

Конструктор класса range.

Параметры
  • start (int) – начальное значение (по умолчанию 0);

  • stop (int) – конечное значение (не включается в результат);

  • step (int) – шаг изменения (по умолчанию 1, может быть отрицательным).

В Листинге 3.1.15 приведены примеры генерации числовых последовательностей и их отображение на экране в виде кортежа.

Листинг 3.1.15 - Создание числового диапазона
# 10 чисел (от 0 до 9), начиная с 0 с шагом 1
>>> tuple(range(10))
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

# 10 чисел (от 1 до 10), начиная с 1 с шагом 1
>>> tuple(range(1, 11))
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

# Числа от 0 до 19 с шагом 5
>>> tuple(range(0, 20, 5))
(0, 5, 10, 15)

# Числа от 0 до 20 с шагом 3
>>> tuple(range(0, 20, 3))
(0, 3, 6, 9, 12, 15, 18)

# Числа от 0 до -9 с шагом -1
>>> tuple(range(0, -10, -1))
(0, -1, -2, -3, -4, -5, -6, -7, -8, -9)

# Следующие 2 объекта range не содержат чисел (нет чисел от 0 до -1 с шагом 1)
>>> tuple(range(0))
()
>>> tuple(range(1, 0))
()

>>> tuple(range(1, 0, -1))
(1,)

Числовые диапазоны поддерживают те же операции, что и кортежи.

3.1.3.2. Множества

Множество - это неупорядоченная коллекция уникальных элементов.

В Python существует 2 класса для работы с множествами:

  • set (изменяемое множество);

  • frozenset (неизменяемое множество).

Элементы множества должны быть хешируемы.

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

Оба типа обладают различиями, схожими с различиями между списком и кортежем.

class set([iterable])
class frozenset([iterable])

Конструкторы классов set и frozenset соответственно.

Создать множество можно несколькими способами (Листинг 3.1.16).

Листинг 3.1.16 - Создание множества
# 1. Пустое множество создается с помощью функции set()
>>> set()
set()

# 2. Инициализировать множество элементами можно, используя:
#    - фигурные скобки с перечислением элементов;
#    - функцию set(), передав в качестве аргумента любой итерируемый объект.
#    Следует обратить внимание, что т.к. множество - неупорядоченный набор данных,
#    при выводе порядок его элементов может быть произвольным.
>>> {"a", "b", "c"}
{'c', 'b', 'a'}
>>> set([1, 2, 3, 4, 5])
{1, 2, 3, 4, 5}

3.1.3.2.1. Общие операции

class set

Пусть st - множество, на котором вызывается метод.

add(elem)

Добавляем элемент elem в множество st.

remove(elem)

Удаляет элемент elem из множества st. Если элемент не находится в множестве, возникает ошибка.

discard(elem)

Удаляет элемент elem из множества st, если он присутствует в множестве.

pop()

Удаляет произвольный элемент из множества st и возвращает в качестве результата.

clear()

Удаляет все элементы из множества.

3.1.3.2.2. Математические операции

Множества поддерживают математические операции, характерные для множеств (пересечение, объединение и др.), некоторые из которые приведены ниже.

class set

Пусть st - множество, на котором вызывается метод.

union(other, ...)
st | other | ...

Возвращает новое множество - объединение множеств st и other.

intersection(other, ...)
st & other & ...

Возвращает новое множество - пересечение множеств st и other.

difference(other, ...)
st - other - ...

Возвращает новое множество - разность множеств st и other.

isdisjoint(other)

Возвращает True если st не содержит общий элементов с other.

issubset(other)
st <= other

Возвращает True если все элементы st содержатся в other.

st < other

Аналогично st <= other, но множества не должны полностью совпадать.

issuperset(other)
st >= other

Возвращает True если все элементы other содержатся в st.

st > other

Аналогично st >= other, но множества не должны полностью совпадать.

update(other, ...)
st |= other | ...

Добавляет элементы из other в st.

В Листинге 3.1.17 приведен пример работы с множеством.

Листинг 3.1.17 - Пример работы с множеством
>>> a = {2, 4, 6, 8, 10}
>>> b = set(range(11))

>>> a
{8, 10, 2, 4, 6}
>>> b
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
>>>

>>> b.remove(0)
>>> b
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

>>> a.add(12)
>>> a
{2, 4, 6, 8, 10, 12}

>>> a & b
{8, 2, 10, 4, 6}

>>> a | b
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12}

>>> a - b
{12}

>>> b - a
{1, 9, 3, 5, 7}

3.1.3.3. Отображения

Отображение - это неупорядоченная коллекция пар элементов «ключ-значение». В разных языках синонимом отображений являются термины словарь, хеш-таблица или ассоциативный массив.

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

class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)

Конструкторы класса dict.

Создать словарь можно несколькими способами (Листинг 3.1.18).

Листинг 3.1.18 - Создание словаря
# 1. Пустой словарь создается с помощью {} или функции dict()
>>> {}
{}
>>> dict()
{}

# 2. Инициализировать словарь элементами, используя:
#    - фигурные скобки с перечислением элементов в виде 'ключ: значение';
#    - функцию dict(), передав набор пар 'ключ: значение'.
#    Следует обратить внимание, что т.к. множество - неупорядоченный набор данных,
#    при выводе порядок его элементов может быть произвольным.
>>> {"one": 1, "two": 2, "three": 3}
{'two': 2, 'one': 1, 'three': 3}
>>> dict(one=1, two=2, three=3)
{'two': 2, 'one': 1, 'three': 3}

Ниже рассмотрены операции, доступные для словарей.

class dict

Пусть d - словарь, на котором вызывается метод.

d[key]

Возвращает значение словаря для ключа key. Если ключ не существует, возникает ошибка.

get(key[, default])

Возвращает значение словаря для ключа key. Если ключ не существует возвращается значение default или None.

d[key] = value

Устанавливает значение словаря по ключу key. Если ключ не существует, он создается.

items()

Возвращает набор пар «ключ-значение» для словаря d.

keys()

Возвращает набор ключей для словаря d.

values()

Возвращает набор значений для словаря d.

clear()

Удаляет из словаря все элементы.

del d[key]

Удаляет пару «ключ-значение» на основании ключа key.

В Листинге 3.1.19 приведен пример работы со словарем.

Листинг 3.1.19 - Пример работы со словарем
>>> phonebook = {"Петров Петр": "+79102222222"}
>>> phonebook["Иванов Сергей"] = "+79101111111"
>>> phonebook
{'Иванов Сергей': '+79101111111', 'Петров Петр': '+79102222222'}

>>> phonebook["Петров Петр"]
'+79102222222'

# Обновили номер телефона
>>> phonebook["Петров Петр"] = "+79103333333"
>>> phonebook
{'Иванов Сергей': '+79101111111', 'Петров Петр': '+79103333333'}

>>> "Васильев Василий" in phonebook
False

>>> phonebook.get("Васильев Василий", "Номер не найден")
'Номер не найден'

>>> phonebook.keys()
dict_keys(['Иванов Сергей', 'Петров Петр'])
>>> phonebook.values()
dict_values(['+79101111111', '+79103333333'])

3.1.4. Еще про объекты и операции

3.1.4.1. Общие функции

Все объекты независимо от типа поддерживают ряд общих функций.

id(object)

Возвращает уникальный идентификатор object (для реализации CPython - адрес в памяти).

x is y

Возвращает True, если x и y указывают на один и тот же объект.

help([object])

Отображает справку для object.

type(object)

Возвращает тип object.

isinstance(object, class-or-type-or-tuple)

Возвращает True, если object является классом или подклассом class-or-type-or-tuple.

3.1.4.2. Проверка типов

Для того, чтобы проверить, какой тип имеет тот или иной объект можно воспользоваться функциями type() или isinstance() - использование последней для проверки типа более предпочтительно (Листинг 3.1.20).

Листинг 3.1.20 - Функции type() и isinstance()
>>> a = 5
>>> type(a) is int
True
>>> isinstance(a, int)
True
# isinstance может принимать вторым параметром кортеж проверяемых типов
>>> isinstance(a, (int, float))
True

3.1.4.3. Взаимное преобразование

Все типы поддерживают взаимное преобразование (где оно имеет смысл, например, преобразование списка в кортеж, но не списка в целое число и т.п.), для чего используется конструктор типа с параметром - объектом, который нужно преобразовать. В Листинге 3.1.21 приведены примеры выполнения конвертации.

Листинг 3.1.21 - Взаимное преобразование типов
# 1. Преобразование в строку
#    Строковое представление имеют практически все рассмотренные классы
>>> str(True)
'True'
>>> str(5)
'5'
>>> str(10.43)
'10.43'
>>> str([1, 2, 3, 4, 5])
'[1, 2, 3, 4, 5]'

# 2. Преобразование в целое число
>>> int(10.43)  # int отсекает дробную часть
10
>>> int("5")
5
>>> int(True)
1

# 3. Преобразование в вещественное число
>>> float(5)
5.0
>>> float("10.43")
10.43

# 4. Преобразование в логический тип
#    Всегда возвращает False, для:
#    - None, False;
#    - нулевых чисел;
#    - пустых последовательностей и отображений.
#    - ...
>>> bool(None), bool(0), bool(0.0), bool(""), bool({})
(False, False, False, False, False)
>>> bool(5), bool({1: "первый"})
(True, True)

# 5. Преобразования последовательностей
>>> tuple([1, 2, 3])
(1, 2, 3)

>>> d = dict(one=1, two=2, three=2)
>>> list(d.keys())  # Получаем список ключей
['one', 'three', 'two']
>>> set(d.values())  # И множество значений
{1, 2}
>>>

3.1.4.4. Приоритет операций

Операции над объектами выполняются в определенном порядке:

  1. **.

  2. -x, +x.

  3. * , / , // , %.

  4. +, -.

  5. <, <=, >, >=, !=, ==.

  6. is, is not.

  7. in, not in.

  8. not, and, or.

Изменение порядка можно производить за счет использования скобок, например: (5 + 2) * 3 или (3 * 2)**3.

3.1.4.5. Поверхностное и глубокое копирование

Оператор присваивания копирует ссылку на объект, создавая т.н. поверхностную копию. В ряде случае необходимо создать полную копию объекта (глубокую копию), например, для мутирующих коллекций, чтобы после изменять новую коллекцию без изменения оригинала. Пример различных вариантов копирования приведен в Листинге 3.1.22.

Листинг 3.1.22 - Поверхностное и глубокое копирование объектов
# 1. Поверхностная и глубокая копии
>>> x = [53, 68, ["А", "В", "С"]]

>>> x1 = x  # Поверхностная копия (через присваивание)
>>> x2 = x[:]  # Глубокая копия (создается при срезе)
>>> x3 = x.copy()  # Глубокая копия (через метод copy())
>>>
>>> id(x), id(x1), id(x2), id(x3)
(4813768, 4813768, 4813848, 4813808)
>>> x1 is x, x2 is x, x3 is x
(True, False, False)

# 2. Присваивание копирует ссылки на объекты, создавая объекты при необходимости
#    Проверить можно с помощью функции id()
>>> a = 5
>>> b = a
>>> a, b
(5, 5)
>>> id(a), id(b)
(1431495600, 1431495600)

>>> c = 5
>>> id(a), id(c)
(1431495600, 1431495600)

# При изменении значения 'a', Python не изменяет объект 5
# (оставляя его "как есть", т.к. знает, что он используется другими),
# а создает новый, меняя ссылку у 'a', при этом прочие объекты продолжают ссылаться на 5
>>> a = 10
>>> id(a), id(c)
(1431495680, 1431495600)

# Но с мутирующими типами (например, списком) Python поступает по-другому
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> c = a
>>> id(a), id(b), id(c)
(30431712, 30447736, 30431712)

# При изменении мутирующего типа "изменяются" и указывающие на него объекты -
# т.к. они хранят ссылку на тот же объект!
>>> a[0] = 5
>>> a, b, c
([5, 2, 3], [1, 2, 3], [5, 2, 3])

3.1.4.6. Константы

В Python не существует привычного для, например, Си или Паскаля понятия константы. Вместо этого, значение, которое подразумевается как константа, обозначается заглавными буквами (MEMORY_MAX = 1024), визуально предупреждая, что данное значение менять не следует.

3.1.4.7. Сортировка

Функция sorted() позволяет получить отсортированный объект в виде списка. В Листинге 3.1.23 приведен пример выполнения сортировки для различных типов коллекций.

Листинг 3.1.23 - Пример использования функции sorted()
# 1. Простой список
>>> lst = [1, 8, 2, 5, 0, 3]
>>> sorted(lst)
[0, 1, 2, 3, 5, 8]
>>> sorted(lst, reverse=True)
[8, 5, 3, 2, 1, 0]

# 2. Словарь
# Для словаря sorted() возвращает отсортированный список ключей
>>> phones = {'Иван': '+74951111111',  'Сергей': '+74951111113',  'Кирилл': '+74951111112'}
>>> sorted(phones)
['Иван', 'Кирилл', 'Сергей']

# 3. Сложная сортировка

# Список кортежей: номер элемента, обозначение, название
>>> elements = [(1, "Н", "Водород"), (8, "O", "Кислород"), (53, "I", "Йод")]

# Используя параметр key, sorted() позволяет сортировать список по
# необходимой части коллекции
# Сортировка по наименованию (элемент с индексом 2 в кортеже)
>>> sorted(elements, key=lambda item: item[2])
[(1, 'Н', 'Водород'), (53, 'I', 'Йод'), (8, 'O', 'Кислород')]

# Список чисел
>>> nums = [123, 100, 1001, 234, 515]

# Сортировка по последней цифре числа по убыванию
>>> sorted(nums, key=lambda item: item % 10, reverse=True)
[515, 234, 123, 1001, 100]

3.1.5. Ввод / вывод

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

Для взаимодействия с терминалом в Python существует 2 функции:

input([prompt])str

Печатает строку prompt (без переноса строки и если задана) и ожидает ввода пользователя. Ввод подтверждается клавишей <ENTER>, возвращая строку с введенными данными в качестве результата.

print(*objects, sep=' ', end='\\n', file=sys.stdout, flush=False)

Печатает набор объектов objects, разделенных запятой. При печати все объекты преобразуются в строки.

Параметры
  • sep – разделитель при выводе нескольких объектов (по умолчанию - пробел);

  • end – строка, завершающая вывод (по умолчанию - перенос строки);

  • file – объект вывода (по умолчанию - терминал).

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

Листинг 3.1.24 - Пример использования функций ввода/вывода
# 1. Выдать приветствие пользователю
>>> name = input("Как тебя зовут? ")
Как тебя зовут? Михаил
>>> print("Привет,", name, "!")
Привет, Михаил !

# 2. Получить длину стороны квадрата (целое число) и вычислить площадь
>>> a = int(input("Введите сторону квадрата: "))
Введите сторону квадрата: 15
>>> square = a ** 2
>>> print("Площадь квадрата = {}".format(square))
Площадь квадрата = 225

1

Побочный эффект. URL: https://ru.wikipedia.org/wiki/Побочный_эффект_(программирование).

2

0.30000000000000004 - Floating Point Math. URL: http://0.30000000000000004.com/.

3

Лучано Рамальо. Python. К вершинам мастерства. — М.: ДМК Пресс , 2016. — 768 с.: ISBN: 978-5-97060-384-0, 978-1-491-94600-8.