- PVSM.RU - https://www.pvsm.ru -
Коллекция в Python — программный объект (переменная-контейнер), хранящая набор значений одного или различных типов, позволяющий обращаться к этим значениям, а также применять специальные функции и методы, зависящие от типа коллекции.
Частая проблема при изучении коллекций заключается в том, что разобрав каждый тип довольно детально, обычно потом не уделяется достаточного внимания разъяснению картины в целом, не проводятся чёткие сходства и различия между типами, не показывается как одну и туже задачу решать для каждой из коллекций в сравнении.
Вот именно эту проблему я хочу попытаться решить в данном цикле статей – рассмотреть ряд подходов к работе со стандартными коллекциями в Python в сравнении между коллекциями разных типов, а не по отдельности, как это обычно показывается в обучающих материалах. Кроме того, постараюсь затронуть некоторые моменты, вызывающие сложности и ошибки у начинающих.
Для кого: для изучающих Python и уже имеющих начальное представление о коллекциях и работе с ними, желающих систематизировать и углубить свои знания, сложить их в целостную картину.
Будем рассматривать стандартные встроенные коллекционные типы данных в Python: список (list), кортеж (tuple), строку (string), множества (set, frozenset), словарь (dict). Коллекции из модуля collections рассматриваться не будут, хотя многое из статьи должно быть применимым и при работе с ними.
Индексированность – каждый элемент коллекции имеет свой порядковый номер — индекс. Это позволяет обращаться к элементу по его порядковому индексу, проводить слайсинг («нарезку») — брать часть коллекции выбирая исходя из их индекса. Детально эти вопросы будут рассмотрены в дальнейшем в отдельной статье.
Уникальность – каждый элемент коллекции может встречаться в ней только один раз. Это порождает требование иммутабельности (неизменности) используемых типов данных для каждого элемента, например, таким элементом не может быть список.
Мутабельность (изменяемость) коллекции — позволяет добавлять в коллекцию новых членов или удалять их. Иммутабельная коллекция неизменна после ее создания.
a = {}
print(type(a)) # <class 'dict'>
b = {1, 2, 3}
print(type(b)) # <class 'set'>
c = {'a': 1, 'b': 2}
print(type(c)) # <class 'dict'>
Разобравшись в классификацией, рассмотрим что можно делать с любой стандартной коллекцией независимо от её типа (в примерах список и словарь, но это работает и для всех остальных рассматриваемых стандартных типов коллекций):
# Зададим исходно список и словарь (скопировать перед примерами ниже):
my_list = ['a', 'b', 'c', 'd', 'e', 'f']
my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
print(my_list) # ['a', 'b', 'c', 'd', 'e', 'f']
print(my_dict) # {'a': 1, 'c': 3, 'e': 5, 'f': 6, 'b': 2, 'd': 4}
# Не забываем, что порядок элементов в неиндексированных коллекциях не сохраняется.
print(len(my_list)) # 6
print(len(my_dict)) # 6 - для словаря пара ключ-значение считаются одним элементом.
print(len('ab c')) # 4 - для строки элементом является 1 символ
x in s — вернет True, если элемент входит в коллекцию s и False — если не входит
Есть и вариант проверки не принадлежности: x not in s, где есть по сути, просто добавляется отрицание перед булевым значением предыдущего выражения.
my_list = ['a', 'b', 'c', 'd', 'e', 'f']
print('a' in my_list) # True
print('q' in my_list) # False
print('a' not in my_list) # False
print('q' not in my_list) # True
Для словаря возможны варианты, понятные из кода ниже:
my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
print('a' in my_dict) # True - без указания метода поиск по ключам
print('a' in my_dict.keys()) # True - аналогично примеру выше
print('a' in my_dict.values()) # False - так как 'а' — ключ, не значение
print(1 in my_dict.values()) # True
Можно ли проверять пары? Можно!
print(('a',1) in my_dict.items()) # True
print(('a',2) in my_dict.items()) # False
Для строки можно искать не только один символ, но и подстроку:
print('ab' in 'abc') # True
В данном случае, в цикле будут последовательно перебираться элементы коллекции, пока не будут перебраны все из них.
for elm in my_list:
print(elm)
for elm in my_dict:
# При таком обходе словаря, перебираются только ключи
# равносильно for elm in my_dict.keys()
print(elm)
for elm in my_dict.values():
# При желании можно пройти только по значениям
print(elm)
Но чаще всего нужны пары ключ(key) — значение (value).
for key, value in my_dict.items():
# Проход по .items() возвращает кортеж (ключ, значение),
# который присваивается кортежу переменных key, value
print(key, value)
Чтобы этого избежать подобных побочных эффектов, можно, например, итерировать копию коллекции:
for elm in list(my_list):
# Теперь можете удалять и добавлять элементы в исходный список my_list,
# так как итерация идет по его копии.
print(min(my_list)) # a
print(sum(my_dict.values())) # 21
Ряд методов у коллекционных типов используется в более чем одной коллекции для решения задач одного типа.
my_list = [1, 2, 2, 2, 2, 3]
print(my_list.count(2)) # 4 экземпляра элемента равного 2
print(my_list.count(5)) # 0 - то есть такого элемента в коллекции нет
my_list = [1, 2, 2, 2, 2, 3]
print(my_list.index(2)) # первый элемент равный 2 находится по индексу 1 (индексация с нуля!)
print(my_list.index(5)) # ValueError: 5 is not in list - отсутствующий элемент выдаст ошибку!
my_set = {1, 2, 3}
my_set_2 = my_set.copy()
print(my_set_2 == my_set) # True - коллекции равны - содержат одинаковые значения
print(my_set_2 is my_set) # False - коллекции не идентичны - это разные объекты с разными id
my_set = {1, 2, 3}
print(my_set) # {1, 2, 3}
my_set.clear()
print(my_set) # set()
set_a = {1, 2, 3}
set_b = {2, 1} # порядок элементов не важен!
set_c = {4}
set_d = {1, 2, 3}
print(set_a.isdisjoint(set_c)) # True - нет общих элементов
print(set_b.issubset(set_a)) # True - set_b целиком входит в set_a, значит set_b - подмножество
print(set_a.issuperset(set_b)) # True - set_b целиком входит в set_a, значит set_a - надмножество
# При равенстве множеств они одновременоо и подмножество и надмножество друг для друга
print(set_a.issuperset(set_d)) # True
print(set_b.issubset(set_d)) # True
В зависимости от стоящих задач, один тип коллекции можно конвертировать в другой тип коллекции. Для этого, как правило достаточно передать одну коллекцию в функцию создания другой (они есть в таблице выше).
my_tuple = ('a', 'b', 'a')
my_list = list(my_tuple)
my_set = set(my_tuple) # теряем индексы и дубликаты элементов!
my_frozenset = frozenset(my_tuple) # теряем индексы и дубликаты элементов!
print(my_list, my_set, my_frozenset) # ['a', 'b', 'a'] {'a', 'b'} frozenset({'a', 'b'})
Это ограничение можно обойти, создав словарь комбинируя ключи со значениями с использованием zip():
my_keys = ('a', 'b', 'c')
my_values = [1, 2] # Если количество элементов разное -
# будет отработано пока хватает на пары - лишние отброшены
my_dict = dict(zip(my_keys, my_values))
print(my_dict) # {'a': 1, 'b': 2}
my_tuple = ('a', 'b', 'c')
my_str = ''.join(my_tuple)
print(my_str) # abc
my_list = [1, [2, 3], 4]
my_set = set(my_list) # TypeError: unhashable type: 'list'
Самые мощные и гибкие способы — генераторы коллекций будут рассмотрены в отдельной статье, так как там много ньюансов и вариантов использования, на которых редко заостряют внимание и требуется детальный разбор.
Автор: DaneSoul
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/231477
Ссылки в тексте:
[1] morff: https://habrahabr.ru/users/morff/
[2] Источник: https://habrahabr.ru/post/319164/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.