Коллекции в Python. Часть I
Списки (кратко), кортежи (кратко), множества, словари и всё, что с ними связано
Just notes
Здесь опишу не совсем очевидные для меня вещи (на момент, когда я о них узнал).
Если в функцию filter()
передаётся lambda
-функция, то она работает медленнее list comprehensions
. В случае же, когда в filter()
помещаются встроенные методы (например str.alpha
), то, наоборот, filter()
работает быстрее, чем списочные выражения.
Следующие строки кода являются эквивалентными: 'Super' 'sonic'
, 'Super' + 'sonic'
. Согласно документации, строковые литералы, которые являются частью одного выражения и имеют только пробелы между ними, будут неявно преобразованы в один строковый литерал.
Синглтон - это паттерн проектирования, гарантирующий, что у класса будет только один экземпляр.
Функция-критерий, которая возвращает значение True или False, называется предикатом.
Итератор - итерируемый объект (например <map object at 0x...>
).
Коллекциями в языке Python принято называть типы данных, в том или ином виде хранящие ссылки на ряд других объектов.
Сравнение строк происходит по старшинству в алфавите, а старше та буква, которая ближе к концу алфавита.
print(("NO", "YES")[num1.issuperset(num2)])
- в квадратных скобках мы получаем результат логического выражения (True
- 1 или False
- 0). Значит после кортежа будет либо [0]
, либо [1]
- индекс элемента, который мы выберем из самого кортежа.
Чтобы не использовать экранирование при работе с текстом, можно воспользоваться raw strings, т.е. вместо такого кода: path = 'C:\\new\\text.txt'
, использовать код: path = r'C:\new\text.txt'
.
При вызове метода мы используем скобки: (например) close()
, а при вызове свойства (атрибута) скобок нет closed
. Методы совершают действия, а свойства возвращают информацию об объекте.
При конвертации строки в число, функция int()
игнорирует пробелы и символы табуляции, перевода строки и т.п.
Если использовать строчные методы islower()
/isupper()
для строки, состоящей только из небуквенных символов, вернётся False
.
Списки
Списки изменяемы; в них допускается выход на границы, просто возьмется весь список до конца; список может содержать элементы разных типов данных; списки - ссылочный тип даных.
Если мы хотим копировать список letters = ['a', 'b', 'c', 'd']
, мы можем сделать это следующими способами:
new_letters = letters[:]
new_letters = list(letters)
new_letters = letters.copy()
join()
или распаковать print(*student)
Списочные методы и операторы:
- метод
append()
добавляет новый элемент в конец списка; - метод
extend()
расширяет один список другим списком; - метод
insert()
вставляет значение в список в заданной позиции; - метод
index()
возвращает индекс первого элемента, значение которого равняется переданному в метод значению; - метод
remove()
удаляет первый элемент, значение которого равняется переданному в метод значению; - метод
pop()
удаляет элемент по указанному индексу и возвращает его; - метод
count()
возвращает количество элементов в списке, значения которых равны переданному в метод значению; - метод
reverse()
инвертирует порядок следования значений в списке, то есть меняет его на противоположный; - метод
copy()
создает поверхностную копию списка.; - метод
clear()
удаляет все элементы из списка; - оператор
del
позволяет удалять элементы списка по определенному индексу.
Методы строк, работающие со списками:
- Метод
split()
разбивает строку на слова, используя в качестве разделителя последовательность пробельных символов, символ табуляции (\t
) или символ новой строки (\n
). - Метод
join()
собирает строку из элементов списка, используя в качестве разделителя строку, к которой применяется метод.
text = [word.strip('.,!?:;-') for word in input().lower().split()]
Матрицы
Индексы i и j элементов на главной диагонали квадратной матрицы связаны соотношением i = j. На побочной диагонали: i + j + 1 = n (или j = n - i - 1), где n — размерность матрицы.
Заметим также, что:
- если элемент находится выше главной диагонали, то i < j, если ниже – i > j.
- если элемент находится выше побочной диагонали, то i + j + 1 < n, если ниже - i + j + 1 > n.
Если мы вводим элементы построчно, то может задать матрицу так:
|
|
Кортежи
Кортежи являются неизменяемыми списками. В литеральной форме кортеж записывается в виде последовательности элементов в круглых скобках, а список – в квадратных.
Для создания кортежа с единственным элементом после значения элемента ставят замыкающую запятую: my_tuple = (1,)
.
Важно понимать: список внутри кортежа можно изменить. Списки являются ссылочными типами данных, поэтому в кортеже хранится ссылка на список, которая не меняется при изменении самого списка.
Кортежи поддерживают:
- доступ к элементу по индексу (только для получения значений элементов);
- методы, в частности
index()
,count()
; - встроенные функции, в частности
len()
,sum()
,min()
иmax()
; - срезы;
- оператор принадлежности
in
; - операторы конкатенации (
+
) и повторения (*
).
Чтобы присвоить переменным значения элементов кортежа, можно воспользоваться следующим кодом (кол-во переменных должно совпадать с кол-вом элементов кортежа):
|
|
Однако, если необходимо получить лишь какие-то отдельные значения, то в качестве “ненужных” переменных позволено использовать символ нижнего подчеркивания _
.
Есть способ собрать сразу несколько значений в одну переменную. Это делается при помощи звездочки перед именем переменной.a, b, *tail = 1, 2, 3, 4, 5, 6
- в этом случае в переменной a
будет записана единица, в переменной b
— двойка, а в переменной tail
— список, состоящий из всех аргументов, которые не попали в предыдущие переменные. В данном случае tail
будет равен [3, 4, 5, 6]
. tail
всегда будет списком, даже когда в него попадает лишь один элемент или даже ноль.
Звездочка может быть только у одного аргумента, но необязательно у последнего.
Если нужно распаковать единственное значение в кортеже, после имени переменной должна идти запятая. Приведенный ниже код:
|
|
|
|
Множества
Общая информация
Множество – структура данных, организованная так же, как математические множества.
Особенности:
- все элементы множества различны (уникальны), два элемента не могут иметь одинаковое значение;
- множества неупорядочены, то есть элементы не хранятся в каком-то определенном порядке;
- элементы множества должны относиться к неизменяемым типам данных;
- хранящиеся в множестве элементы могут иметь разные типы данных.
Чтобы создать множество, нужно перечислить его элементы через запятую в фигурных скобках:
|
|
Пустое множество создаётся, например, через set()
.
При выводе множества порядок элементов может отличаться от существовавшего при его создании, поскольку множества — неупорядоченные коллекции данных.
Встроенная функция set()
помимо создания пустого множества может преобразовывать некоторые типы объектов в множества.
В неё можно передать один аргумент, который, в свою очередь, должен быть итерируемым объектом (таким как список, кортеж или строковое значение). Отдельные элементы объекта, передаваемого в качестве аргумента, становятся элементами множества:
|
|
|
|
|
|
Если требуется создать множество, в котором каждый элемент — строковое значение, содержащее более одного символа, то используем код: myset = set(['aaa', 'bbbb', 'cc'])
.
Проверить принадлежит ли какой-либо объект множеству можно с помощью оператора in
:
|
|
Индексация, конкатенация, умножение на число и срезы недоступны для множеств, а значит перебор элементов по индексу не получится, поэтому, например, в цикле, мы должны перебирать сами элементы из множества.
Чтобы вывести все элементы множества, мы можем его распаковать (при этом не гарантируется, что вывод будет упорядоченным):
|
|
Если мы хотим упорядочить вывод множества, можем воспользоваться встроенной функцией sorted()
(возвращает список):
|
|
Встроенная функция sorted()
имеет опциональный параметр reverse
. Если установить этот параметр в значение True
, произойдет сортировка по убыванию.
Также есть второй параметр key
, с помощью которого можно указать функцию, по которой будет происходить сортировка (например, int
или len
). Важно, что функция при этом пишется без скобок, как это обычно происходит.
Методы множеств
- Для добавления нового элемента в множество используется метод
add()
; - Метод
remove()
удаляет элемент из множества с генерацией исключения (ошибки) в случае, если такого элемента нет; - Метод
discard()
удаляет элемент из множества без генерации исключения (ошибки), если элемент отсутствует; - Метод
pop()
удаляет и возвращает случайный элемент из множества с генерацией исключения (ошибки) при попытке удаления из пустого множества; - Метод
clear()
удаляет все элементы из множества.
Методы, НЕ изменяющие сами множества
union()
- объединение множеств.
|
|
Для объединения двух множеств можно также использовать оператор |
.
|
|
intersection()
- пересечение множеств.
Альтернатива: оператор&
.difference()
- разность множеств.
Альтернатива: оператор-
.symmetric_difference()
- симметрическая разность множеств.
Альтернатива: оператор^
.
Методы, ИЗМЕНЯЮЩИЕ множества
update()
- изменяет исходное множество по объединению.
Аналогичный результат получается, если использовать оператор|=
.intersection_update()
- изменяет исходное множество по пересечению.
Аналогичный результат получается, если использовать оператор&=
.difference_update()
- изменяет исходное множество по разности.
Аналогичный результат получается, если использовать оператор-=
.symmetric_difference_update()
- изменяет исходное множество по симметрической разности.
Аналогичный результат получается, если использовать оператор^=
.
Все основные операции над множествами выполняются двумя способами: при помощи метода или соответствующего ему оператора. Различие заключается в том, что метод может принимать в качестве аргумента не только множество (тип данных set
), но и любой итерируемый объект (список, строку, кортеж и т.д.)
|
|
|
|
Некоторые методы (union()
, intersection()
, difference()
) и операторы (|
, &
, -
, ^
) позволяют совершать операции над несколькими множествами сразу.
Оператор ^
симметрической разности позволяет использовать несколько множеств, а метод symmetric_difference()
– нет.
Приоритет операторов в порядке убывания (верхние операторы имеют более высокий приоритет, чем нижние):
Оператор | Описание |
---|---|
- | разность |
& | пересечение |
^ | симметрическая разность |
| | объединение |
Другие методы
issubset()
- используется для определения, является ли одно из множеств подмножеством другого. ВозвращаетTrue
илиFalse
.
|
|
Для определения, является ли одно из множеств подмножеством другого, также применяются операторы <=
(нестрогое подмножество) и <
(строгое подмножество). Следующий код аналогичен предыдущему по функционалу:
|
|
issuperset()
- используется для определения, является ли одно из множеств надмножеством другого. ВозвращаетTrue
илиFalse
.
В качестве альтернативы используются операторы>=
(нестрогое надмножество) и>
(строгое надмножество).isdisjoint()
- используется для определения отсутствия общих элементов в множествах. ВозвращаетTrue
илиFalse
.
Данные методы могут принимать в качестве аргумента не только set()
, но и любой итерируемый объект (список, строку, кортеж…). В то же время они могут применяться только к set()
или неизменяемому множеству (тип данных frozenset
). При этом операторы >
, <
, >=
, <=
требуют наличия в качестве операндов множества.
Генератор множеств
Чтобы создать множество, содержащее цифры введённого числа, можно воспользоваться следующей конструкцией: digits = {int(c) for c in input()}
Общий вид генератора множеств следующий:
{выражение for переменная in последовательность}
,
где выражение – некоторое выражение, как правило, зависящее от использованной в списочном выражении переменной, которым будут заполнены элементы множества; переменная – имя некоторой переменной; последовательность – последовательность значений, которые она принимает (любой итерируемый объект).
В генераторах множеств можно использовать условный оператор. Например, если требуется создать множество, заполненное только цифрами некоторой строки, то мы можем написать такой код: digits = {int(d) for d in 'abcd12ef78ghj90' if d.isdigit()}
Если же нужно включить else
, то используется тернарный условный оператор:alnums = {int(d) if d.isdigit() else ord(d) for d in 'abcd12ef78ghj90'}
Frozenset
Тип коллекций frozenset()
- это неизменяемое множество. Создание неизменяемых множеств:
|
|
Над замороженными множествами можно производить все операции, которые можно производить над обычными множествами (само собой, если операция не изменяет исходное множество). Результатом операций над замороженными множествами будут также замороженные множества.
Будучи изменяемыми, обычные множества не могут быть элементами других множеств. Замороженные множества являются неизменяемыми, а значит могут быть элементами других множеств.
Словари
Общая информация
Словари (тип данных dict
) – изменяемые коллекции элементов с произвольными индексами – ключами. Если в списках элементы индексируются целыми числами, начиная с 0, то в словарях — уникальными ключами, в том числе в виде строк.
В словарях нет привычных индексов (0, 1, 2, …)!
Ключи должны быть неизменяемым типом данных, а тип данных значения - произволен.
Словари принципиально отличаются от списков по структуре хранения в памяти. Список — последовательная область памяти, то есть все его элементы (указатели на элементы) действительно хранятся в указанном порядке, расположены последовательно. Благодаря этому и можно быстро «прыгнуть» к элементу по его индексу. В словаре же используется специальная структура данных — хеш-таблица. Она позволяет вычислять числовой хеш от ключа и использовать обычные списки, где в качестве индекса элемента берется этот хеш.
Чтобы создать словарь, нужно перечислить его элементы (пары ключ-значение) через запятую в фигурных скобках, как и элементы множества. Первым указывается ключ, после двоеточия – значение, доступное в словаре по этому ключу. Приведенный ниже код создает словарь, в котором ключом служит строка – название языка программирования, а значением – имя создателя языка.
|
|
Извлекать значение словаря слудует также, как если бы мы извлекали элемент списка, но вместо индекса пишем ключ в квадратных скобках:
|
|
В качестве ключа можно указать выражение. Python вычислит его значение и обратится к искомому элементу:
|
|
Если ключи словаря – строки без каких-либо специальных символов, то для создания словаря можно использовать функцию dict()
. Приведённый ниже код создает словарь с тремя элементами, ключами которого служат строки ’name’, ‘age’, ‘job’, а значениями – ‘Timur’, 28, ‘Teacher’.
|
|
Создавать словари можно на основе списков кортежей или кортежей списков. Первый элемент списка или кортежа станет ключом, второй — значением.
Если необходимо создать словарь, каждому ключу которого соответствует одно и то же значение, можно воспользоваться методом fromkeys()
. Приведенный ниже код создает словарь с тремя элементами, где ключи — строки ’name’, ‘age’, ‘job’, а соответствующие им значения: ‘Missed information’, ‘Missed information’, ‘Missed information’.
|
|
Если методу fromkeys()
не передать второй параметр, то по умолчанию присваивается значение None
.
Пустой словарь
Пустой словарь можно создать так:
dict1 = {}
dict2 = dict()
Начиная с версии Python 3.6, словари являются упорядоченными, то есть сохраняют порядок следования ключей в порядке их внесения в словарь.
Основы работы со словарями
- Оператор
in
позволяет проверить, содержит ли словарь заданный ключ; - Встроенная функция
sum()
принимает в качестве аргумента словарь с числовыми ключами и вычисляет сумму его ключей; - Встроенные функции
min()
иmax()
принимают в качестве аргумента словарь и находят минимальный и максимальный ключ соответственно, при этом ключ может принадлежать к любому типу данных, для которого возможны операции порядка<
,<=
,>
,>=
(числа, строки, и т.д.); - Словари можно сравнивать между собой операторами
==
и!=
. Равные словари имеют одинаковое количество элементов и содержат равные элементы (ключ: значение); - Срезы, операция конкатенации и умножения на число недоступны для словарей.
Перебор элементов словаря
Вывод ключей:
|
|
Вывод значений:
|
|
- Словарный метод
keys()
возвращает список ключей всех элементов словаря:
|
|
|
|
Словарный метод
values()
возвращает список значений всех элементов словаря.Словарный метод
items()
возвращает список всех элементов словаря, состоящий из кортежей пар (ключ, значение).
items()
, keys()
, values()
возвращают не совсем обычные списки. Типы этих списков называются итераторами – dict_items
, dict_keys
, dict_values
, соответственно, в отличие от обычных списков list
. Методы обычных списков недоступны для списков типа dict_items
, dict_keys
, dict_values
. Нужно использовать явное преобразование с помощью функции list()
для получения доступа к методам списков.Если требуется вывести только ключи словаря, то мы так же можем использовать операцию распаковки словаря: print(*capitals, sep="\n")
Сортировка по ключам выполняется с использованием функции sorted()
(возвращает отсортированный список ключей, а не словарь):
|
|
Для сортировки словаря по значениям можно использовать функцию sorted()
вместе с методом items()
(возвращает не словарь, а отсортированный по значениям список кортежей):
|
|
Методы и операторы словарей
Чтобы изменить значение по определенному ключу в словаре, достаточно использовать индексацию вместе с оператором присваивания. При этом если ключ уже присутствует в словаре, его значение заменяется новым, если же ключ отсутствует – то в словарь будет добавлен новый элемент.
|
|
- Для того чтобы избежать возникновения ошибки в случае отсутствия ключа в словаре, можно использовать метод
get()
, способный кроме ключа принимать и второй аргумент – значение, которое вернется, если заданного ключа нет. Когда второй аргумент не указан, то метод в случае отсутствия ключа возвращаетNone
.
|
|
|
|
- Метод
update()
реализует своеобразную операцию конкатенации для словарей. Он объединяет ключи и значения одного словаря с ключами и значениями другого. При совпадении ключей в итоге сохранится значение словаря, указанного в качестве аргумента методаupdate()
.
|
|
- Метод
setdefault()
позволяет получить значение из словаря по заданному ключу, автоматически добавляя элемент словаря, если он отсутствует.
Метод принимает два аргумента:
- key: ключ, значение по которому следует получить, если таковое имеется в словаре, либо создать.
- default: значение, которое будет использовано при добавлении нового элемента в словарь.
get()
только получает значение, не меняя словарь, в то время как setdefault()
не только получает значение, но и изменяет словарь.- С помощью оператора
del
можно удалять элементы словаря по ключу:del info['email']
(если удаляемого ключа в словаре нет, возникнет ошибкаKeyError
). - Метод
pop()
удаляет элемент словаря по ключу, возвращая его значение:email = info.pop('email')
(при отсутствии ключа также возвращает ошибку, если не передать второй аргумент). - Метод
popitem()
удаляет из словаря последний добавленный элемент и возвращает удаляемый элемент в виде кортежа (ключ, значение). - Метод
clear()
удаляет все элементы из словаря:info.clear()
. - Метод
copy()
создает поверхностную копию словаря:info_copy = info.copy()
(оператор присваивания (=) не копирует словарь, а лишь присваивает ссылку на старый словарь новой переменной.).
Вложенные словари
Чтобы обратиться к элементу вложенного словаря, нужно указать ключи в нескольких квадратных скобках (подобно спискам).
Генераторы словарей
Общий вид: {ключ: значение for переменная in последовательность}
Примеры использования:
- Чтобы создать словарь, где ключи – числа от 0 до 5, а значения – квадраты ключей, можем воспользоваться следующим кодом:
squares = {i: i**2 for i in range(6)}
; - Для вычисления ключа и значения в генераторе словаря могут быть использованы выражения:
|
|
- Извлечение из словаря элементов с определенными ключами:
|
|
- Мы также можем использовать генераторы словарей для создания вложенных словарей:
|
|
|
|
В генераторах словарей можно использовать условный оператор. Приведенный ниже код создает словарь, ключами которого являются четные числа от 0 до 9, а значениями – квадраты ключей: squares = {i: i**2 for i in range(10) if i % 2 == 0}
(можно обойтись и без условного оператора, установив параметр step
в функции range()
).
