Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Назначение коллекций (Collections) в Python
Модуль collections предоставляет специализированные контейнеры, которые более эффективны и удобны, чем встроенные типы (list, dict, set, tuple) для конкретных задач.
Основная проблема
Встроенные типы — не всегда идеальны
# Проблема 1: Работа с очередью
queue = []
# Добавляем в конец
queue.append(1)
queue.append(2)
queue.append(3)
# Берём из начала — неэффективно!
first = queue.pop(0) # O(n) — все элементы сдвигаются!
print(first) # 1
# Проблема: при 1000 элементов pop(0) очень медленно
# Проблема 2: Словарь, который помнит порядок вставки
old_dict = {}
old_dict['z'] = 1
old_dict['a'] = 2
old_dict['m'] = 3
# В Python < 3.7 порядок был случайным
# В Python >= 3.7 порядок гарантирован, но это не явно видно
# Проблема 3: Счёт элементов
data = [1, 1, 1, 2, 2, 3, 3, 3, 3]
counts = {}
for item in data:
if item in counts:
counts[item] += 1
else:
counts[item] = 1
print(counts) # {1: 3, 2: 2, 3: 4}
# Много кода для простой операции
Решение: Collections
from collections import deque, defaultdict, Counter, OrderedDict, namedtuple
# Вот как это становится просто
Основные типы из Collections
1. deque (Double-Ended Queue)
Для чего: очереди и стеки с O(1) операциями с обоих концов
from collections import deque
# Проблема: очередь с list
queue_list = []
for i in range(1000):
queue_list.append(i) # O(1)
for i in range(1000):
queue_list.pop(0) # O(n) — медленно!
# Решение: deque
queue = deque()
for i in range(1000):
queue.append(i) # O(1)
for i in range(1000):
item = queue.popleft() # O(1) — быстро!
# Реальный пример: обработка задач
tasks = deque(["task1", "task2", "task3"])
while tasks:
task = tasks.popleft() # Берём первый
print(f"Processing {task}")
if task == "task1":
tasks.append("subtask1") # Добавляем новый в очередь
2. Counter
Для чего: подсчёт элементов
from collections import Counter
# Проблема: подсчёт вручную
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(word_count) # {"apple": 3, "banana": 2, "cherry": 1}
# Решение: Counter
word_count = Counter(words)
print(word_count) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
# Бонус: most_common()
most_frequent = word_count.most_common(2)
print(most_frequent) # [('apple', 3), ('banana', 2)]
# Реальный пример: аналитика
logs = [
"user_123_logged_in",
"user_456_logged_in",
"user_123_purchased",
"user_789_logged_in",
"user_123_logged_out",
]
event_types = Counter([log.split('_')[-1] for log in logs])
print(event_types)
# Counter({'in': 3, 'purchased': 1, 'out': 1})
most_common_event = event_types.most_common(1)
print(f"Most common: {most_common_event[0][0]}")
# Most common: in
3. defaultdict
Для чего: словарь со значениями по умолчанию
from collections import defaultdict
# Проблема: KeyError при доступе к несуществующему ключу
students = {}
students['Alice'] = [90, 85]
students['Bob'] = [75, 80]
score = students['Charlie'] # KeyError!
# Решение 1: проверка
if 'Charlie' in students:
score = students['Charlie']
else:
score = []
# Решение 2: get()
score = students.get('Charlie', [])
# Решение 3: defaultdict (самое красивое)
students = defaultdict(list) # Заранее говорим, что по умолчанию list
students['Alice'].append(90)
students['Alice'].append(85)
students['Bob'].append(75)
# Автоматически создаёт пустой list для новых студентов
students['Charlie'].append(95) # Работает!
print(dict(students))
# {'Alice': [90, 85], 'Bob': [75], 'Charlie': [95]}
# Реальный пример: группировка данных
from collections import defaultdict
orders = [
{'user_id': 1, 'amount': 100},
{'user_id': 2, 'amount': 150},
{'user_id': 1, 'amount': 50},
{'user_id': 3, 'amount': 200},
]
user_orders = defaultdict(list)
for order in orders:
user_orders[order['user_id']].append(order['amount'])
print(dict(user_orders))
# {1: [100, 50], 2: [150], 3: [200]}
# Вычисляем сумму по пользователям
user_totals = defaultdict(float)
for order in orders:
user_totals[order['user_id']] += order['amount']
print(dict(user_totals))
# {1: 150.0, 2: 150.0, 3: 200.0}
4. namedtuple
Для чего: создание простых immutable классов
from collections import namedtuple
# Проблема: много кода для простого объекта
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
point = Point(10, 20)
print(point.x) # 10
# Решение: namedtuple (одна строка!)
Point = namedtuple('Point', ['x', 'y'])
point = Point(10, 20)
print(point.x) # 10
print(point[0]) # 10 (можно как tuple)
print(point) # Point(x=10, y=20)
# Бонусы
x, y = point # Распаковка как tuple
point_dict = point._asdict() # Преобразование в dict
print(point_dict) # {'x': 10, 'y': 20}
# Реальный пример: результаты поиска
SearchResult = namedtuple('SearchResult', ['id', 'title', 'score'])
results = [
SearchResult(1, "Python Guide", 0.95),
SearchResult(2, "Python Tutorial", 0.87),
SearchResult(3, "Java Guide", 0.75),
]
for result in results:
print(f"ID: {result.id}, Title: {result.title}, Score: {result.score}")
# Сортировка по score
top_result = max(results, key=lambda r: r.score)
print(f"Best match: {top_result.title}")
5. OrderedDict
Для чего: явное сохранение порядка (в Python < 3.7)
from collections import OrderedDict
# В Python 3.7+ обычный dict тоже сохраняет порядок
# Но OrderedDict имеет дополнительные методы
config = OrderedDict()
config['host'] = 'localhost'
config['port'] = 8000
config['debug'] = True
for key, value in config.items():
print(f"{key}: {value}") # Гарантированный порядок
# Метод move_to_end() — уникален для OrderedDict
config.move_to_end('debug', last=False) # Переместить в начало
print(list(config.keys())) # ['debug', 'host', 'port']
6. ChainMap
Для чего: объединение нескольких словарей
from collections import ChainMap
# Сценарий: настройки с fallback values
defaults = {'host': 'localhost', 'port': 8000, 'debug': False}
env_vars = {'host': '0.0.0.0', 'port': 3000}
user_config = {'debug': True}
# Без ChainMap: нужно вручную объединять
config = {**defaults, **env_vars, **user_config}
print(config) # {'host': '0.0.0.0', 'port': 3000, 'debug': True}
# С ChainMap: создаём цепочку приоритета
config = ChainMap(user_config, env_vars, defaults)
print(config['host']) # '0.0.0.0' (из env_vars, т.к. приоритет выше)
print(config['debug']) # True (из user_config, наивысший приоритет)
print(config['nonexistent']) # KeyError (не во всех словарях)
print(config.get('nonexistent')) # None
# Реальный пример: конфигурация приложения
app_config = ChainMap(
os.environ, # Приоритет 1: environment variables
user_settings, # Приоритет 2: пользовательские настройки
defaults, # Приоритет 3: значения по умолчанию
)
Когда использовать что
| Коллекция | Когда использовать | Главное преимущество |
|---|---|---|
deque | Очереди, стеки | O(1) пушинг/попинг с обоих концов |
Counter | Подсчёт элементов | Простой и быстрый подсчёт |
defaultdict | Группировка, аккумуляция | Нет KeyError, читаемый код |
namedtuple | Простые структуры данных | Иммутабелен, синтаксис как класс |
OrderedDict | Если нужны методы вроде move_to_end | Явная семантика порядка |
ChainMap | Настройки с fallback | Elegantly merged lookup |
Пример использования вместе
from collections import deque, Counter, defaultdict
# Обработка логов
logs = deque(open('app.log').readlines()) # Читаем в очередь
error_counts = Counter() # Подсчитываем ошибки
errors_by_user = defaultdict(list) # Группируем по пользователям
while logs:
log_line = logs.popleft() # Берём из очереди эффективно
if 'ERROR' in log_line:
error_type = log_line.split('ERROR: ')[1].split('\n')[0]
error_counts[error_type] += 1
user_id = log_line.split('USER: ')[1].split(' ')[0]
errors_by_user[user_id].append(error_type)
print("Most common errors:", error_counts.most_common(3))
print("Errors by user:", dict(errors_by_user))
Вывод
Коллекции из модуля collections — это essential tools для написания:
- Более читаемого кода
- Более эффективного кода
- Более Pythonic кода
Они решают частые задачи с минимумом кода и максимумом производительности. Если вы используете встроенные типы для сложных операций, вероятно, в collections есть лучший инструмент.