Типы контейнеров в Python и их особенности
Выбор структуры данных в Python
Как сохранить последовательность элементов с возможностью изменения?
Наиболее эффективное решение для большинства задач - список (list). Список представляет упорядоченную изменяемую коллекцию, допускающую дублирование элементов. Его можно расширять, сокращать, изменять элементы по индексу.
my_list = [1, 2, 3]
my_list.append(4)
my_list.insert(0, 0)
print(my_list) # [0, 1, 2, 3, 4]
значения списка числа python (итерация по значениям списка чисел в python)
Типичные ошибки: путаница с индексами (выход за границы), изменение списка во время итерации. Решение: использовать срез или копию для обхода, а для удаления во время итерации - list comprehension.
Как сделать данные неизменяемыми для безопасности?
Кортеж (tuple) - неизменяемый аналог списка. Он занимает меньше памяти и может использоваться как ключ словаря.
my_tuple = (1, 2, 3)
# my_tuple[0] = 10 # TypeError
print(my_tuple.count(1)) # 1
словарь set python (словарь и set в python)
Важно: кортеж с одним элементом требует запятую: (1,). Иначе это просто число в скобках.
Как хранить только уникальные элементы и выполнять быстрые операции принадлежности?
Множество (set) - неупорядоченная коллекция без дубликатов. Поддерживает математические операции объединения, пересечения, разности.
my_set = {1, 2, 3, 2}
print(my_set) # {1, 2, 3}
print(2 in my_set) # True
my_set.add(4)
Python dict set (словарь и множество в python)
Нельзя поместить в set изменяемые элементы (списки, словари). Для этого используется frozenset. Порядок элементов не гарантируется.
Как связать ключи со значениями для быстрого доступа?
Словарь (dict) - отображение ключ-значение. Ключи должны быть хешируемыми (неизменяемыми). Словари очень эффективны для поиска по ключу.
my_dict = {'a': 1, 'b': 2}
my_dict['c'] = 3
print(my_dict.get('d', 0)) # 0
типы структур python (типы структур данных в python)
Изменяемый объект (например, список) не может быть ключом. При итерации по словарю не стоит изменять его размер. Для значения по умолчанию удобно использовать defaultdict.
Как организовать эффективную очередь FIFO или стек LIFO?
Двусторонняя очередь (collections.deque) оптимизирована для добавления и удаления с обоих концов. Для стека подходит и обычный список, но deque обеспечивает O(1) для pop(0) и popleft().
from collections import deque
dq = deque([1, 2, 3])
dq.append(4)
dq.appendleft(0)
print(dq) # deque([0, 1, 2, 3, 4])
кортеж чисел python (кортеж чисел в python)
Не следует использовать deque для произвольного доступа по индексу (медленнее, чем список).
Как создать хешируемое множество для использования в качестве ключа словаря?
Неизменяемое множество (frozenset) - аналог set, но не может быть изменён. Его можно помещать в другие множества или использовать как ключ словаря.
fs = frozenset([1, 2, 3])
d = {fs: "value"}
print(d[fs]) # value
язык программирования python массивы (массивы (списки) в python)
frozenset не поддерживает методы добавления/удаления.
Как определить легковесную структуру с именованными полями?
namedtuple из collections создаёт класс с именованными атрибутами, занимающий столько же памяти, сколько кортеж. Удобно для хранения данных без написания отдельного класса.
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y) # 10 20
Поля namedtuple неизменяемы. Для изменяемых полей лучше использовать dataclass или обычный класс.
Расширенные примеры работы со структурами данных
Ниже приведены более сложные и менее распространённые приёмы использования встроенных и модульных контейнеров Python.
Как использовать deque для скользящего окна?
Очередь с ограниченной длиной автоматически удаляет элементы с противоположного конца.
from collections import deque
window = deque(maxlen=3)
for i in range(6):
window.append(i)
print(list(window))
[0]
[0, 1]
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
Как объединить несколько словарей с помощью ChainMap?
ChainMap позволяет просматривать несколько словарей как единое целое, не создавая новый словарь.
from collections import ChainMap
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
combined = ChainMap(d1, d2)
print(combined['b']) # берётся из первого словаря: 2
print(list(combined.keys()))
2
['b', 'a', 'c']
Как подсчитать частоту элементов с Counter?
Counter - подкласс dict для подсчёта хешируемых объектов.
from collections import Counter
data = ['a', 'b', 'a', 'c', 'b', 'b']
cnt = Counter(data)
print(cnt.most_common(2)) # [('b', 3), ('a', 2)]
cnt.update(['a', 'a'])
print(cnt['a']) # 4
[('b', 3), ('a', 2)]
4
Как использовать defaultdict для вложенных структур?
defaultdict автоматически вызывает фабричную функцию для отсутствующего ключа.
from collections import defaultdict
nested = defaultdict(lambda: defaultdict(int))
nested['user1']['likes'] += 1
nested['user1']['shares'] += 2
print(dict(nested))
{'user1': {'likes': 1, 'shares': 2}}
Как хранить упорядоченные уникальные элементы с сохранением порядка добавления?
В Python 3.7+ обычные словари сохраняют порядок вставки, но для явной гарантии можно использовать OrderedDict (доступен в collections).
from collections import OrderedDict
od = OrderedDict()
od['z'] = 1
od['a'] = 2
od['b'] = 3
for k in od:
print(k, end=' ') # z a b
z a b
Как создать неизменяемый словарь с помощью types.MappingProxyType?
Обёртка над словарём, запрещающая изменения, но отражающая изменения исходного словаря.
from types import MappingProxyType
base = {'key': 'value'}
proxy = MappingProxyType(base)
print(proxy['key']) # value
# proxy['new'] = 1 # TypeError
base['key'] = 'new_value'
print(proxy['key']) # new_value
value
new_value
Как использовать array для эффективного хранения чисел одного типа?
Модуль array предоставляет компактные массивы примитивных типов (int, float, char).
from array import array
arr = array('i', [1, 2, 3]) # signed int
arr.append(4)
print(arr.tolist()) # [1, 2, 3, 4]
# arr[0] = 'a' # TypeError
[1, 2, 3, 4]
Как использовать dataclass для изменяемых именованных структур?
Декоратор dataclass автоматически генерирует методы __init__, __repr__ и другие.
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int = 0
p = Person('Alice', 30)
p.age = 31
print(p) # Person(name='Alice', age=31)
Person(name='Alice', age=31)