# Python. Структуры данных: список, кортеж, множество, словарь
Python содержит встроенные типы данных: списки, кортежи, словари.
# Списки
Чтобы создать список используйте квадратные скобки или функцию list() :
my_list1 = [] # Пустой список my_list2 = list() # Пустой список
Список сохраняет порядок элементов с которым создаётся или в котором элементы добавляются. Списки являются последовательностями и поддерживают доступ к элементам по индексу, другие свойства последовательностей будут описаны в следующих главах.
Первый элемент списка находится под индексом 0, последний — на единицу меньше длины списка.
>>> name = ["obi", "ike", "nwosu"] >>> name[0] 'obi' >>> name[1] 'ike' >>> name[2] 'nwosu'
1
2
3
4
5
6
7
Метод append() добавляет элемент в список.
>>> name = ["obi", "ike", "nwosu"] >>> name.append("nkem") >>> names ["obi", "ike", "nwosu", "nkem"]
Метод insert() добавляет элемент в любое место списка.
>>> name = ["obi", "ike", "nwosu"] >>> name.insert(1, "nkem") >>> names ["obi", "nkem", "ike", "nwosu"]
Оператор + объединяет два и более списка.
>>> name = ["obi", "ike", "nwosu"] >>> name1 = ["James"] >>> name + name1 ["obi", "ike", "nwosu", "James"]
Для просмотра всех методов списка запустите команду help(list) .
# Кортежи
Кортеж тоже является последовательностью и создается элементами разделёнными запятыми:
>>> companies = "Google", "Microsoft", "Tesla" >>> companies ('Google', 'Microsoft', 'Tesla')
При определении непустого кортежа скобки не обязательны, но они становятся обязательными когда кортеж является частью большего выражения. Пустой кортеж создаётся пустой парой скобок:
>>> companies = () >>> type(companies) class 'tuple'>
При определении кортежа с одним элементом запятая за ним обязательна.
>>> company = "Google", >>> type(company) class 'tuple'> >>> company = ("Google",) >>> type(company) class 'tuple'>
1
2
3
4
5
6
7
Пропуск запятой означает что задано обычное значение, не кортеж.
>>> company = ("Google") >>> company 'Google' >>> type(company) class 'str'>
1
2
3
4
5
6
Кортежи индексируются как списки, но неизменямы.
>>> companies = ("Google", "Microsoft", "Palantir") >>> companies[0] 'Google' >>> companies[0] = "Boeing" Traceback (most recent call last): File "", line 1, in module> TypeError: 'tuple' object does not support item assignment
1
2
3
4
5
6
7
В тоже время, если элементом кортежа является изменяемые объект, такой как список, то он может быть изменен.
>>> companies = (["lockheedMartin", "Boeing"], ["Google", "Microsoft"]) >>> companies (['lockheedMartin', 'Boeing'], ['Google', 'Microsoft']) >>> companies[0].append("SpaceX") >>> companies (['lockheedMartin', 'Boeing', 'SpaceX'], ['Google', 'Microsoft'])
1
2
3
4
5
6
# Множества
Множества это неупорядоченные коллекции объектов не содержащие дубликатов. Пустое множество создаётся функцией set() или фигурными скобками <> . Множества неупорядоченны поэтому к элементам множества нельзя обратится по индексу. Множества, за исключением frozen set, изменяемы.
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] >>> basket_set = set() >>> basket_set set() >>> basket_set.update(basket) >>> basket_set 'pear', 'orange', 'apple', 'banana'> >>> basket_set.add("clementine") >>> basket_set 'pear', 'orange', 'apple', 'banana', 'clementine'> >>> basket_set.remove("apple") >>> basket_set 'pear', 'orange', 'banana', 'clementine'>
1
2
3
4
5
6
7
8
9
10
11
12
13
# Словари
Словарь в Python похож на ассоциативный массив или хеш-таблицу в других языках. Словари индексируются по неизменяемому ключу. Для создания словаря используются фигурные скобки <> или функция dict() . Словарь — неупорядоченное множество пар ключ-значение в которых ключ уникален. Пример инициализации словаря:
ages = "obi": 24, "nkem": 23, "Chris": 23 >
Основные операции словаря это сохранение значения по ключу и доступ к значению по ключу. Доступ к значению осуществляется через квадратные скобки:
>>> ages["obi"] 24
Словари изменяемы: значения связанные с ключами могут менятся, добавлятся и удалятся.
Структуры данных Python не ограничиваются приведёнными в этом разделе. Например, модуль collections содержит очереди, деки и другие коллекции. В то же время структуры приведённые в этом разделе используются в большинстве приложений на Python.
Используйте функцию help с параметром в виде названия типа данных для детального изучения типа.
help(list) help(tuple) help(set) help(dict)
Упаковка данных в Python — кортеж tuple
Вас зовут get_contacts и вы умеете находить контакты человека по email-адресу: его адрес, имя и номер телефона. Вы не прочь поделиться информацией с другими, но Python вам это запрещает. Нельзя возвращать так много данных разом, результат у функции может быть только один. Вы можете выбрать что-то одно, самое важное: адрес, имя, или телефон человека. Или можете проявить изобретательность и упаковать все свои данные в одну переменную.
Как упаковать данные в кортеж
Для функции get_contacts(email) доступны несколько способов упаковки данных в более сложную структуру: словарь dict() , кортеж tuple() и еще несколько других. Рассмотрим подробнее последний вариант — tuple , или по-русски кортеж.
Предположим, вы вызвали функцию get_contacts(‘dmitry@example.com’) , она нашла такого человека и хочет вернуть его контакты:
full_name = 'Никифоров Дмитрий Анатольевич' city = 'Москва' phone_number = '929-876-54-32'
Функция создает кортеж — tuple() —, чтобы поместить в него все контакты:
contacts = (full_name, city, phone_number)
Круглые скобки и запятые указывают Python, что из перечисленных переменных full_name , city и phone_number нужно создать новую структуру данных:
print(type(contacts)) # выведет print(contacts)
Последний вызов print() выведет на экран такое:
('Никифоров Дмитрий Анатольевич', 'Москва', '929-876-54-32')
Теперь функция get_contacts сможет вернуть любое количество данных. Все они будут упакованы в один кортеж — tuple .
Что делать, если получили tuple
Разберем как работать с tuple на примере стандартной функции divmod . Она возвращает результат деления с остатком:
divmod(100, 3) # выведет (33, 1) divmod(2, 3) # выведет (0, 2)
Функция divmod возвращает кортеж из двух чисел — результата целочисленного деления и остаток от деления.
Мы можем сохранить результат в переменную:
div_tuple = divmod(100, 3) print(div_tuple) # выведет (33, 1)
Добраться до каждого из двух чисел можно по индексу:
div_tuple = divmod(100, 3) print(div_tuple[0]) # выведет 33 print(div_tuple[1]) # выведет 1
Индексы в коде [0] и [1] сильно осложняют чтение, поэтому полезно давать говорящие названия:
div_tuple = divmod(100, 3) int_division = div_tuple[0] remainder = div_tuple[1] print(int_division) # выведет 33 print(remainder) # выведет 1
Распаковка кортежа
При работе с кортежами очень часто приходится доставать все данные в отдельные переменные:
int_division = div_tuple[0] remainder = div_tuple[1]
Это встречается настолько часто, что в Python ввели упрощенную короткую запись:
(int_division, remainder) = divmod(100, 3) print(int_division) # выведет 33 print(remainder) # выведет 1
Запись похожа на создание кортежа — те же скобки и запятые, но работает это в обратную сторону. Называется “распаковкой”.
Если в кортеже больше одного элемента, то скобки указывать необязательно. Python любит чистый код:
int_division, remainder = divmod(100, 3) print(int_division) # выведет 33 print(remainder) # выведет 1
Последняя форма записи распаковки наиболее распространена и рекомендуется к использованию.
Скобки не обязательно указывать и при создании кортежа, но этот прием может усложнить чтение кода, будьте с ним осторожны:
contacts = full_name, city, phone_number
В коде внутри функций часто встречается еще более короткая запись:
return full_name, city, phone_number
Вызов return сообщает интерпретатору Python, что функция завершает свою работу и хочет вернуть результат. А все перечисленное справо от return будет упаковано в кортеж — tuple .
Как добавить элемент в кортеж
Добавить в кортеж ничего нельзя. Он неизменяемый, однажды созданный кортеж никак нельзя изменить. Зато можно создать новый:
old_tuple = (1, 2) new_tuple = old_tuple + (3, 4) print(new_tuple) # Выведется (1, 2, 3, 4)
Если вы хотите добавить только один элемент, то велик соблазн написать так:
old_tuple = (1, 2) new_tuple = old_tuple + 3
TypeError: can only concatenate tuple (not "int") to tuple
Эта ошибка значит, что вы попытались сложить кортеж и число, а Python умеет складывать только кортежи. Поэтому придётся сделать из вашего элемента кортеж, но с одним элементом внутри:
old_tuple = (1, 2) new_tuple = old_tuple + (3,) print(new_tuple) # Выведется (1, 2, 3)
Что ещё почитать
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.
Как именованный кортеж добавить в словарь?
В функцию передают список именнованных кортежей с котиками. Функция должна возвращать список словарей с «ключами» именованного кортежа. У меня в итоге добавляется только последний котик. И можно ли как-нибудь напрямую взять «ключи» кортежа и сделать из них ключи словаря чтобы не прописывать вручную строчку для каждого ключа?
import collections Cat = collections.namedtuple("Cat", ["nickname", "age", "owner"]) def convert_list(cats): to_dict = <> list_of_dict_cats = [] if isinstance(cats[0], tuple): for cat in cats: to_dict['nickname'] = cat.nickname to_dict['age'] = cat.age to_dict['owner'] = cat.owner list_of_dict_cats.append(to_dict) print(list_of_dict_cats) convert_list([Cat("Mick", 5, "Sara"), Cat("Barsik", 7, "Olga"), Cat("Simon", 3, "Yura")])
Отслеживать
задан 27 янв в 6:08
196 11 11 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Нужно перенести создание словаря to_dict внутрь цикла. Из-за того что вы создаете словарь до цикла, в список каждый раз добавляется один и тот же словарь. Все элементы списка у вас — это один и тот же словарь, и изменения в словаре отображаются во всех элементах списка.
Проверку isinstance(cats[0], tuple) , если она действительно нужна, лучше внести в цикл, т.к. то что первый элемент списка — tuple , не гарантирует, что другие элементы — тоже tuple . К тому же, при типа значения первого элемента у вас отсутствует проверка, что список не пустой, но если внести проверку в цикл, то дополнительная проверка будет не нужна.
И то что объект — tuple не гарантирует, что у объекта будут поля nickname , age , owner , поэтому лучше явно проверять, что объект относится к классу Cat
for cat in cats: if isinstance(cat, Cat): to_dict = <> to_dict['nickname'] = cat.nickname to_dict['age'] = cat.age to_dict['owner'] = cat.owner list_of_dict_cats.append(to_dict)
Также, для преобразования namedtuple в словарь можно использовать метод _asdict :
for cat in cats: if isinstance(cat, Cat): list_of_dict_cats.append(cat._asdict())
Ну и по условию вам нужно создать функцию, которая должна возвращать список словарей, а вы его печатаете, вместо этого нужно делать return list_of_dict_cats , а результат функции уже печатать:
import collections Cat = collections.namedtuple("Cat", ["nickname", "age", "owner"]) def convert_list(cats): list_of_dict_cats = [] for cat in cats: if isinstance(cat, Cat): list_of_dict_cats.append(cat._asdict()) return list_of_dict_cats print(convert_list([Cat("Mick", 5, "Sara"), Cat("Barsik", 7, "Olga"), Cat("Simon", 3, "Yura")]))
Обзор возможностей словаря dict в Python
Словари встречаются и в других языках как, только называются по разному, например «ассоциативная память» или «ассоциативные массивы». В отличие от последовательностей, которые индексируются диапазоном чисел, словари индексируются ключами, которые могут быть любого неизменяемого типа. Строки и числа всегда могут быть ключами. Кортежи могут использоваться в качестве ключей, если они содержат только строки, числа или кортежи. Если кортеж содержит любой изменяемый объект прямо или косвенно, он не может использоваться в качестве ключа.
Нельзя использовать списки в качестве ключей словаря, так как списки могут быть изменены на месте с помощью индексов, срезов или методов, таких как append() и extend() .
Лучше всего рассматривать словарь как набор пар «ключ-значение» с требованием, чтобы ключи были уникальными в пределах одного словаря. Пара фигурных скобок создает пустой словарь: ‘<>‘ . Размещение разделенного запятыми списка пар key: value в фигурных скобках добавляет пары key: value в словарь. Так же словари записываются в коде.
Основное применение словаря — это хранение значения с некоторым ключом и извлечение значения из словаря, заданного ключом. Также можно удалить пару key:value используя инструкцию del .
Если в словарь добавляется новый ключ, который уже используется, старое значение, связанное с этим ключом, будет забыто. Извлечение значения с помощью несуществующего ключа является ошибкой. Если ошибки при извлечении значений не желательны, то необходимо использовать метод словаря dict.get() . Метод dict.get() возвращает None или указанное значение по умолчанию, если ключа не существует.
Выполнение list(d) в словаре возвращает список всех ключей, используемых в словаре, в порядке вставки. Если вы хотите, чтобы он был отсортирован, просто используйте sorted(d) .
Варианты использования словарей dict в Python.
- Основные операции со словарями;
- Варианты создания словаря;
- Списки-представления словаря;
- Выражение-генератор словаря;
- Использование функций в качестве значений словаря;
- Имитация конструкции switch/case словарем Python.
Основные операции со словарями Python.
>>> tel = 'jack': 4098, 'sape': 4139> >>> tel['guido'] = 4127 >>> tel # # извлечение значения по ключу >>> tel['jack'] # 4098 # извлечение значения по ключу со значением # по умолчанию (если такого ключа нет) >>> tel.get('joy', 2021) # 2021 # удаление и добавление элементов словаря >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel # # преобразование ключей словаря в список >>> list(tel) # ['jack', 'guido', 'irv'] # сортировка словаря >>> sorted(tel) # ['guido', 'irv', 'jack'] # проверка наличия ключа в словаре >>> 'guido' in tel # True >>> 'jack' not in tel # False
Варианты создания словаря Python.
Класс dict() строит словарь непосредственно из последовательностей пар ключ-значение:
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) #
Когда ключи являются строками, то проще указать пары, используя ключевые аргументы:
>>> dict(sape=4139, guido=4127, jack=4098) #
Для создания словарей из произвольных ключей и значений можно использовать генераторы-словарей.
>>> x: x**2 for x in (2, 4, 6)> # # словарь генерируется из 2-х списков >>> x: y for x, y in zip(['a', 'b', 'c'], [1, 2, 3])> #
Списки-представления словаря Python.
Словарь содержит очень полезные методы, которые называются списки-представления dict.keys() , dict.values() , dict.items() , которые изменяются динамически. Это значит, что все изменения, такие как удаление, изменение или добавление значений в словаре сразу отражаются на соответствующем представлении.
>>> x = 'one': 1, 'two': 2, 'three': 3, 'four': 4> >>> keys = x.keys() >>> values = x.values() >>> items = x.items() # Производим операции со словарем 'x', а все # отражается на списках-представлениях >>> x['one'] = 0 >>> values # dict_values([0, 2, 3, 4]) >>> items # dict_items([('one', 0), ('two', 2), ('three', 3), ('four', 4)]) >>> x['ten'] = 10 >>> keys # dict_keys(['one', 'two', 'three', 'four', 'ten']) >>> values # dict_values([0, 2, 3, 4, 10]) >>> items # dict_items([('one', 0), ('two', 2), ('three', 3), ('four', 4), ('ten', 10)]) >>> del x['three'] >>> items # dict_items([('one', 0), ('two', 2), ('four', 4), ('ten', 10)]) >>> values # dict_values([0, 2, 4, 10]) >>> keys # dict_keys(['one', 'two', 'four', 'ten'])
Обратите внимание, что присвоение значений keys , values и items происходит только в начале кода, а отслеживание изменений в словаре идет до конца кода.
>>> x = 'one': 0, 'two': 20, 'three': 3, 'four': 4> >>> keys = x.keys() >>> 'one' in keys # True >>> values = x.values() >>> 3 in values # True >>> items = x.items() >>> ('three', 3) in items # True
Выражение-генератор словаря Python.
При помощи выражения генератора словаря можно сделать много интересного.
Пример обмена местами (инверсии) ключей и значений словаря, при этом помним, что ключом может быть только неизменяемый объект.
>>> d = 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5> >>> y: x for x, y in d.items()> #
Пример фильтра ключей и значений словаря. Отберем ключи и значения словаря, отвечающие определенным условиям. В результате будет создан новый словарь.
>>> d = 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5> # отберем элементы словаря, ключи которых имеют значения 'a' или # 'c' или 'e', а значения этих ключей должны быть больше 1 >>> key: val for key, val in d.items() if key in ('a', 'c', 'e') and val > 1> #
Пример сортировки словаря по значению:
>>> x = 1: 2, 3: 4, 4: 3, 2: 1, 0: 0> >>> k: v for k, v in sorted(x.items(), key=lambda item: item[1])> #
>>> x = 1: 2, 3: 4, 4: 3, 2: 1, 0: 0> >>> dict(sorted(x.items(), key=lambda item: item[1])) #
Использование функций в качестве значений словаря Python.
Так как функции в Python являются объектами, то можно заменить значения ключей словаря функциями и возвращать их, если ключи совпадают.
Очень простой пример.
# словарь с функциями calc = "plus": lambda x, y: x + y, "minus": lambda x, y: x - y, "division": lambda x, y: x / y, # в качестве значения используем # встроенную функцию pow() "power": pow > # типа фабрики функций def action(match, dictionary, default="NO CALC"): for key in dictionary.keys(): if match in key: return dictionary[key] return lambda *x: default >>> plus = action('plus', calc) >>> minus = action('minus', calc) >>> power = action('power', calc) >>> square = action('square', calc) >>> plus(5, 4) # 9 >>> minus(5, 4) # 1 >>> power(3, 3) # 27 >>> square(1, 1) 'NO CALC' >>> square(1) 'NO CALC'
Можно использовать словарь с функциями напрямую, если лень создавать фабрику (далее будет рассмотрена фабрика на collections.defaultdict() и лямбда-функциях):
# словарь с функциями calc = "plus": lambda x, y: x + y, "minus": lambda x, y: x - y, "division": lambda x, y: x / y, # в качестве значения используем # встроенную функцию pow() "power": pow > >>> calc['plus'](5, 4) # 9 >>> calc['minus'](5, 4) # 1 >>> calc['division'](9, 3) # 3.0 >>> calc['power'](3, 3) # 27
Передача аргументов функциям, расположенным в словаре очень проста. Однако что, если нужно манипулировать аргументами перед передачей их в функцию? В этом случае код может выглядеть так:
def handle_event(e): print(f"Обработка события в 'handler_event' с помощью: e>") return e def handle_other_event(e): print(f"Обработка события в 'handle_other_event' с помощью: e>") return e functions = "event1": lambda arg: handle_event(arg["some-key"]), "event2": lambda arg: handle_other_event(arg["some-other-key"]), > event = "some-key": "value", "some-other-key": "different value", > print(functions["event1"](event)) # Обработка события в 'handler_event' с помощью: value # value print(functions["event2"](event)) # Обработка события в 'handle_other_event' с помощью: different value # different value
Имитация конструкции switch/case словарем Python.
В случае, если необходимо эмулировать поведение операторов switch/case , то следует рассмотреть возможность использования значения по умолчанию, когда ключ словаря отсутствует. Плюс ко всему здесь будем использовать диспетчеризацию для функций, требующих более одной строки кода (лямбда-функции хороши для простых случаев).
Вот как это сделать:
from collections import defaultdict def add(x, y): return x + y def mul(x, y): return x * y cases = defaultdict(lambda *args: lambda *a: "Invalid option", "add": add, "mul": mul, >) >>> cases["add"](5, 3)) # 8 >>> cases["plus"](5, 3)) # Invalid option
Единственная разница при использовании правильных функций заключается в том, что они должны быть определены вне словаря, потому что Python не допускает встроенных определений функций.
Этот фрагмент использует collections.defaultdict , первый аргумент которого указывает «фабрику по умолчанию«, которая представляет собой функцию, которая будет вызываться, когда ключ не найден. Можно заметить, что здесь используются две лямбда-функции. Первая предназначена для перехвата любого количества переданных ему аргументов, а вторая — для того чтобы вернуть вызываемый объект.
- Встроенный класс dict() .
- Тип dict , словари в Python.
- Методы словарей и поддерживаемые операции.
