Перейти к содержимому

8. Списки, словари и кортежи

Иллюстрация к уроку

# Сортировка
nums = [3, 1, 4, 1, 5, 9, 2, 6]
nums.sort() # изменяет на месте: [1, 1, 2, 3, 4, 5, 6, 9]
sorted(nums) # возвращает новый список
# Сортировка объектов
users = [
{"name": "Вера", "age": 30, "salary": 80000},
{"name": "Анна", "age": 25, "salary": 100000},
{"name": "Гена", "age": 22, "salary": 70000},
]
by_age = sorted(users, key=lambda u: u["age"])
by_salary_desc = sorted(users, key=lambda u: u["salary"], reverse=True)
# Сортировка по нескольким полям
by_age_then_name = sorted(users, key=lambda u: (u["age"], u["name"]))
# Срезы (slices)
nums = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
nums[2:5] # [2, 3, 4]
nums[:3] # [0, 1, 2]
nums[7:] # [7, 8, 9]
nums[::2] # [0, 2, 4, 6, 8] — каждый второй
nums[::-1] # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] — реверс
# Изменение среза
nums[2:5] = [20, 30, 40] # замена элементов
nums[::2] = [0]*5 # каждый второй = 0
# Копирование
original = [1, [2, 3], 4]
shallow = original.copy() # мелкая копия
shallow = original[:] # то же самое
import copy
deep = copy.deepcopy(original) # глубокая копия
# Список как стек (LIFO)
stack = []
stack.append(1) # push
stack.append(2)
stack.append(3)
stack.pop() # pop -> 3
# Список как очередь (FIFO) — но медленно!
# Лучше использовать deque
from collections import deque
queue = deque()
queue.append("первый") # добавить в конец
queue.append("второй")
queue.popleft() # удалить из начала -> "первый"
from collections import Counter, defaultdict, OrderedDict, namedtuple
# Counter — подсчёт элементов
text = "banana"
counts = Counter(text)
# Counter({'a': 3, 'n': 2, 'b': 1})
words = "the cat sat on the mat".split()
word_counts = Counter(words)
word_counts.most_common(3) # [('the', 2), ('cat', 1), ('sat', 1)]
# defaultdict — словарь с дефолтным значением
graph = defaultdict(list)
graph["A"].append("B") # не нужно проверять наличие ключа
graph["A"].append("C")
graph["B"].append("D")
# Группировка по полю
students = [("Анна", "Python"), ("Борис", "Java"), ("Вера", "Python")]
by_language = defaultdict(list)
for name, lang in students:
by_language[lang].append(name)
# {"Python": ["Анна", "Вера"], "Java": ["Борис"]}
# namedtuple — как dataclass, но проще
Point = namedtuple("Point", ["x", "y"])
p = Point(10, 20)
print(p.x, p.y) # 10 20
print(p[0], p[1]) # 10 20 (как кортеж)
# setdefault — безопасная установка
d = {}
d.setdefault("key", []).append("value") # создаёт ключ если нет
# update — слияние словарей
config = {"debug": False, "port": 8000}
overrides = {"debug": True, "host": "localhost"}
config.update(overrides)
# {"debug": True, "port": 8000, "host": "localhost"}
# Python 3.9+: оператор |
merged = config | overrides
# Удаление с получением значения
value = config.pop("debug", None) # None если ключа нет
# Сортировка словаря
d = {"banana": 3, "apple": 5, "cherry": 1}
sorted_by_value = dict(sorted(d.items(), key=lambda x: x[1]))
# {"cherry": 1, "banana": 3, "apple": 5}
# Инвертирование словаря
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
# {1: "a", 2: "b", 3: "c"}
# Глубокое обновление
def deep_update(base: dict, updates: dict) -> dict:
"""Рекурсивное обновление словаря."""
for key, value in updates.items():
if isinstance(value, dict) and key in base:
deep_update(base[key], value)
else:
base[key] = value
return base

Dataclasses — современный способ хранения данных

Заголовок раздела «Dataclasses — современный способ хранения данных»
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class User:
name: str
email: str
age: int
role: str = "user" # с дефолтным значением
tags: list[str] = field(default_factory=list) # изменяемый дефолт
created_at: datetime = field(default_factory=datetime.now)
def is_admin(self) -> bool:
return self.role == "admin"
user = User(name="Яша", email="[email protected]", age=2)
print(user.name) # "Яша"
print(user.is_admin()) # False
# dataclass автоматически создаёт __init__, __repr__, __eq__
print(user)
# User(name='Яша', email='[email protected]', age=2, role='user', ...)
# Frozen dataclass — неизменяемый
@dataclass(frozen=True)
class Point:
x: float
y: float
def distance(self, other: "Point") -> float:
return ((self.x - other.x)**2 + (self.y - other.y)**2) ** 0.5
p1 = Point(0, 0)
p2 = Point(3, 4)
p1.distance(p2) # 5.0
# p1.x = 10 — ОШИБКА! frozen
from typing import TypedDict, Required, NotRequired
class UserDict(TypedDict):
name: str
email: str
age: int
role: NotRequired[str] # опциональное поле
user: UserDict = {"name": "Яша", "email": "[email protected]", "age": 2}
# IDE покажет ошибку если структура неверна
from collections import defaultdict, Counter
from dataclasses import dataclass, field
@dataclass
class Order:
id: int
user_id: int
product: str
amount: float
status: str
orders = [
Order(1, 101, "Python Book", 29.99, "completed"),
Order(2, 102, "JS Book", 24.99, "completed"),
Order(3, 101, "React Course", 49.99, "pending"),
Order(4, 103, "Python Book", 29.99, "completed"),
Order(5, 102, "Python Book", 29.99, "cancelled"),
]
# Статистика по продуктам
completed = [o for o in orders if o.status == "completed"]
by_product = Counter(o.product for o in completed)
# Counter({"Python Book": 2, "JS Book": 1})
# Выручка по пользователям
revenue = defaultdict(float)
for order in completed:
revenue[order.user_id] += order.amount
top_users = sorted(revenue.items(), key=lambda x: x[1], reverse=True)
# Задание 1: Инвентарь магазина
inventory = [
{"name": "Молоко", "price": 89.5, "category": "dairy", "qty": 50},
{"name": "Хлеб", "price": 45.0, "category": "bakery", "qty": 30},
{"name": "Сыр", "price": 350.0, "category": "dairy", "qty": 15},
{"name": "Кефир", "price": 65.0, "category": "dairy", "qty": 40},
{"name": "Булка", "price": 35.0, "category": "bakery", "qty": 60},
]
# Реализуй:
# 1. Общая стоимость инвентаря (price * qty)
# 2. Средняя цена по категориям
# 3. Топ-3 товара по стоимости запаса
# 4. Функция search(query) — поиск по названию (без учёта регистра)
# Задание 2: Dataclass
# Создай dataclass Product с полями: name, price, category, in_stock
# Добавь метод discount(percent) -> "Product" — возвращает новый продукт со скидкой

В следующем уроке — ООП в Python!