Кортежи встречаются не только в программировании, но и в математике. В математике под кортежем обычно понимают упорядоченную совокупность элементов, то есть совокупность, порядок элементов которой фиксирован. В кортеже мы точно знаем, какой элемент является первым, какой – вторым, и так далее.
Внешне кортежи несильно отличаются от списков. Единственное внешнее отличие – элементы кортежа заключаются в круглые, а не в квадратные скобки.
my_tuple = (1, 2, 4, 6, 9)
К элементам кортежа можно обращаться точно так же, как к элементам списка:
my_tuple[0]
Но, несмотря на кажущееся сходство, кортежи и списки – принципиально разные объекты. Главное отличие кортежей от списков заключается в том, что кортежи – неизменяемые объекты. Другими словами, изменять элементы кортежа нельзя. Проверим:
my_tuple[2] = 65
Иногда это свойство бывает полезным (некоторая «защита» от изменений), иногда – не очень, но для нас пока важно познакомиться с разными объектами в Python, чтобы потом не удивляться. Ведь многие более продвинутые функции могут возвращать результат или, наоборот, принимать на вход только кортежи или только списки.
При желании кортеж можно превратить в список:
list(my_tuple)
И наоборот:
tuple([1,2,3])
Если посмотреть на методы, применяемые к кортежам (например, набрать my_tuple.
и нажать Tab), то можно заметить, что методов для кортежей сильно меньше по сравнению с методами для списков. Во многом это связано с тем, что кортеж нельзя изменить. Но вот «склеивать» кортежи, создавая при этом новый, легко:
(1, 3) + (7, 8)
Обсуждая словари в Python, удобно проводить аналогию с обычными словарями (бумажными или электронными). Что такое словарь? Перечень из пар: слово-значение или слово-список значений, если значений несколько. Вот и словарь в Python – это объект, структура данных, которая позволяет хранить пары соответствий.
Давайте представим, что нам нужно создать словарь, который мы будем использовать для программки к мюзиклу "Notre Dame de Paris". Будем записывать в словарь prog
пары соответствий герой-актер.
prog = {'Gringoire' : 'Pelletier',
'Frollo' : 'Lavoie', 'Phoebus': 'Fiori'}
Первый элемент в каждой паре (до двоеточия) назвается ключом (key), второй элемент в каждой паре (после двоеточия) – значением (value). Посмотрим на словарь:
prog
Как и в случае со списками или кортежами, к элементам словаря можно обращаться. Только выбор элемента производится не по индексу, а по ключу: сначала указываем название словаря, а потом в квадратных скобках – ключ, по которому мы хотим вернуть значение. Например, выясним, кто играет роль Феба:
prog['Phoebus']
А что будет, если мы запросим элемент по ключу, которого нет в словаре?
prog['Esmeralda']
В глубине души Python начинает грустно петь "Where is she, your Esmeralda?", но вместо эмоций выдает сухое KeyError. Ошибка ключа – ну нет в словаре элемента с ключом Esmeralda!
Теперь представьте себе такую ситуацию: у нас есть список героев (ключей) и мы хотим в цикле вернуть по ним в фамилии актеров (значения). Какого-то одного из героев нет. Что произойдет? На каком-то этапе Python выдаст ошибку, мы вывалимся из цикла, и на этом наша работа остановится. Обидно, да? Чтобы такого избежать, получать значение по ключу можно другим способом – используя метод .get()
:
prog.get('Esmeralda') # ни результата, ни ошибки
Если выведем результат на экран явно, с помощью print()
, увидим, что в случае, если пары с указанным ключом в словаре нет, Python выдаст значение None
:
print(prog.get('Esmeralda'))
Удобство метода .get()
заключается в том, что мы сами можем установить, какое значение будет возвращено, в случае, если пары с выбранным ключом нет в словаре. Так, вместо None
мы можем вернуть строку Not found
, и ломаться ничего не будет:
prog.get('Esmeralda', 'Not found')
Возвращаемое значение в случае, если запись с указанным ключом отсутствует в словаре, необязательно должно быть строкой, можно было бы поставить какое-нибудь число или значение False
:
print(prog.get('Esmeralda', 99))
print(prog.get('Esmeralda', False))
Но недостающий элемент мы всегда можем добавить!
prog['Esmeralda'] = 'Segara'
prog
Внимание: Если элемент с указанным ключом уже существует, новый с таким же ключом не добавится! Ключ – это уникальный идентификатор элемента. Если мы добавим в словарь новый элемент с уже существующим ключом, мы просто изменим старый – словари являются изменяемыми объектами. Например, так (изменения в программке prog
):
prog['Esmeralda'] = 'Noa'
prog
Раз элементами словаря являются пары ключ-значение, наверняка есть способ выбрать из словаря ключи и значения отдельно. Действительно, для этого есть методы .keys()
и values()
. Вызовем сначала все ключи:
prog.keys()
Объект, который мы только что увидели, очень похож на список. Но обычным списком на самом деле не является. Давайте попробуем выбрать первый элемент prog.keys()
:
keys = prog.keys()
keys[0]
Не получается! Потому что полученный объект имеет специальный тип dict_keys
, а не list
. Но это всегда можно поправить, превратив объект dict_keys
в список:
list(keys)[0] # получается!
Аналогичным образом можно работать и со значениями:
prog.values()
Словари могут состоять не только из строк, почти любые объекты могут быть ключами и значениями списка (забегая вперед, значениями – любые, ключами – только неизменяемые). Например, можно создать словарь оценок, состоящий из пар целых чисел, числовой id студента-его оценка.
numbers = {1 : 7, 2 : 8, 3 : 9}
Обращаться к элементам мы будем, естественно, без кавычек, так как ключами являются числа:
numbers[1] # оценка студента с id равным 1
Словари могут состоять из элементов смешанного типа. Например, вместо числового id можно явно записать имя студента:
marks = {"Петя": 6, "Вася": 9}
marks["Петя"]
Ну, и раз уж питоновские словари так похожи на обычные, давайте представим, что у нас есть словарь, где все слова многозначные. Ключом будет слово, а значением ‒ целый список.
my_dict = {'swear' : ['клясться', 'ругаться'],
'dream' : ['спать', 'мечтать']}
По ключу мы получим значение в виде списка:
my_dict['swear']
Так как значением является список, можем отдельно обращаться к его элементам:
my_dict['swear'][0] # первый элемент
Можем пойти дальше и создать словарь, где значениями являются словари! Например, представим, что в некотором сообществе проходят выборы, и каждый участник может проголосовать за любое число кандидатов. Данные сохраняются в виде словаря, где ключами являются имена пользователей, а значениями – пары кандидат-голос.
# '+' - за, '-' - против, 0 - воздержался
votes = {'user1': {'cand1': '+', 'cand2': '-'},
'user2' : {'cand1': 0, 'cand3' : '+'}}
votes
По аналогии с вложенными списками по ключам мы сможем обратиться к значению в словаре, который сам является значением в votes
(да, эту фразу нужно осмыслить):
# берем значение, соответствующее ключу user1, в нем – ключу cand1
votes['user1']['cand1']
А теперь давайте подумаем, как можно вывести на экран элементы словаря по очереди, в цикле. Первая попытка:
for k in prog:
print(k)
Попытка не совсем удалась: на экран были выведены только ключи. А как вывести пары?
Задача: для каждого героя мюзикла из словаря prog
вывести на экран сообщение вида
Fiori plays the role of Phoebus
Решение: вспомним, что мы можем получать значения по ключу, указывая его в квадратных скобках, и проделаем это для всех ключей в словаре:
for k in prog:
print(prog[k], "plays the role of", k)
Упражнение полезное, но, на самом деле, существует специальный метод .items()
, который позволяет обращаться сразу к парам элементов:
for k, v in prog.items():
print(k, v)
Для того, чтобы вывести и ключ, и значение, нужно в цикле for
перечислить две переменные через запятую. И совсем не обязательно называть их k
и v
или key
и value
; Python сам поймет, что первая переменная соответствует ключу, а вторая ‒ значению. Для примера решим поставленную выше задачу с помощью items()
.
for hero, actor in prog.items():
print(actor, "plays the role of", hero)
Если мы посмотрим на prog.items()
, мы увидим, что этот объект очень похож на список, состоящий из кортежей:
prog.items()
Как и случае с методами .keys()
и .values()
, полученный объект не является «обычным» списком. Поэтому при необходимости его нужно будет превратить в список:
list(prog.items())
Метод .items()
полезен, когда мы хотим выбирать из словаря значения, удовлетворяющие определенным условиям. Для разнообразия возьмем другой словарь – словарь с парами студент-оценка:
grades = {"Вася": 7, "Петя" : 9, "Коля" : 8, "Лена" : 8,
"Василиса" : 10}
И выведем на экран имена тех студентов, у которых оценка равна 8:
for name, grade in grades.items():
if grade == 8:
print(name)
Только два человека: Коля и Лена. А как проверить, есть ли в словаре элемент с определенным ключом? Воспользоваться оператором in
:
"Коля" in grades.keys()
"Ваня" in grades.keys()