Глава 6. Словари и множества

210 просмотров
0 лайков
0 в избранном

Что такое словарь

Словарь (dict) — это коллекция пар «ключ-значение». К каждому значению обращаются по ключу, а не по индексу. Создаётся фигурными скобками:

user = {
    "name": "Анна",
    "age": 28,
    "city": "Москва",
}

print(user["name"])    # Анна
print(user["age"])     # 28

Ключи должны быть уникальны и неизменяемы (строки, числа, кортежи). Значения — любые.

Доступ и добавление

user = {"name": "Анна", "age": 28}

# Чтение
print(user["name"])   # Анна

# Обращение к несуществующему ключу — KeyError
# print(user["email"])   # ошибка!

# Безопасный доступ через get()
print(user.get("email"))          # None
print(user.get("email", "нет"))   # "нет" — значение по умолчанию

# Добавление и изменение
user["email"] = "anna@example.com"   # новый ключ
user["age"] = 29                     # изменение существующего

Методы словаря

user = {"name": "Анна", "age": 28, "city": "Москва"}

print(user.keys())    # dict_keys(['name', 'age', 'city'])
print(user.values())  # dict_values(['Анна', 28, 'Москва'])
print(user.items())   # пары (ключ, значение)

# Перебор пар — самый частый сценарий
for key, value in user.items():
    print(f"{key}: {value}")

Удаление

user = {"name": "Анна", "age": 28, "city": "Москва"}

del user["city"]              # удалить по ключу
age = user.pop("age")         # удалить и вернуть значение
user.clear()                  # очистить словарь

update() — слияние

defaults = {"theme": "light", "lang": "ru"}
user_prefs = {"theme": "dark"}

defaults.update(user_prefs)
print(defaults)   # {'theme': 'dark', 'lang': 'ru'}

Проверка наличия ключа

Оператор in проверяет, есть ли ключ в словаре:

user = {"name": "Анна"}

if "email" in user:
    print(user["email"])
else:
    print("Email не указан")

Счётчик через get()

Классическая задача — посчитать, сколько раз встретился каждый элемент. Решается словарём и безопасным чтением через get() с значением по умолчанию 0:

words = ["яблоко", "банан", "яблоко", "груша", "банан", "яблоко"]
counts = {}

for word in words:
    counts[word] = counts.get(word, 0) + 1

print(counts)   # {'яблоко': 3, 'банан': 2, 'груша': 1}

Читается так: «взять текущее значение (или 0, если ключа ещё нет), прибавить единицу и записать обратно».

setdefault() — добавить, если нет

setdefault(key, default) возвращает значение по ключу, а если ключа нет — сначала вставляет default и возвращает его. Для чисел разницы с get() почти нет, а вот для изменяемых значений (список, множество) метод незаменим — он даёт объект, который тут же можно дополнить:

people = [("Москва", "Анна"), ("Питер", "Борис"), ("Москва", "Вера")]
by_city = {}

for city, name in people:
    by_city.setdefault(city, []).append(name)

print(by_city)   # {'Москва': ['Анна', 'Вера'], 'Питер': ['Борис']}

Без setdefault пришлось бы каждый раз писать if city not in by_city: by_city[city] = [].

Словарные выражения

Аналог list comprehension для словарей:

# Квадраты чисел как ключ-значение
squares = {n: n ** 2 for n in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Инвертировать словарь (поменять ключи и значения)
original = {"a": 1, "b": 2}
inverted = {v: k for k, v in original.items()}
# {1: 'a', 2: 'b'}

zip() — склеить два списка

Функция zip() идёт по нескольким последовательностям одновременно и выдаёт кортежи из соответствующих элементов:

keys = ["name", "age", "city"]
values = ["Анна", 28, "Москва"]

for k, v in zip(keys, values):
    print(k, "=", v)
# name = Анна
# age = 28
# city = Москва

Отсюда самый короткий способ собрать словарь из двух списков — передать zip() прямо в dict():

user = dict(zip(keys, values))
print(user)   # {'name': 'Анна', 'age': 28, 'city': 'Москва'}

Если списки разной длины, zip() останавливается на самом коротком — «лишние» элементы просто игнорируются.

Множества (set)

Множество — это коллекция уникальных элементов. Создаётся через set() или фигурные скобки (но не пустые — {} создаёт словарь):

numbers = {1, 2, 3, 2, 1}   # {1, 2, 3} — дубликаты схлопнутся
print(numbers)

# Получить уникальные элементы списка
tags = ["python", "web", "python", "django", "web"]
unique = set(tags)
print(unique)   # {'python', 'web', 'django'}

Операции над множествами

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a & b)    # {3, 4}  — пересечение
print(a | b)    # {1, 2, 3, 4, 5, 6}  — объединение
print(a - b)    # {1, 2}  — разность
print(a ^ b)    # {1, 2, 5, 6}  — симметрическая разность

Проверка принадлежности в множестве очень быстрая (O(1)), поэтому его используют вместо списка для in:

allowed = {"admin", "editor"}    # множество
# allowed = ["admin", "editor"]  # список — медленнее для in

if role in allowed:
    print("Доступ открыт")

Какую структуру выбрать

ЗадачаСтруктура
Упорядоченный набор элементовlist
Неизменяемая последовательностьtuple
Связь ключа со значениемdict
Уникальные элементы, быстрая проверка принадлежностиset
Конфигурация, профиль пользователяdict

Кейс 1: конфигурация приложения

Словарь — естественный способ хранить настройки. Ключи — строки, значения — любые типы:

config = {
    "debug": True,
    "port": 8000,
    "database": {
        "host": "localhost",
        "name": "myapp",
    },
    "allowed_hosts": ["localhost", "127.0.0.1"],
}

# Вложенный доступ
print(config["database"]["host"])   # localhost
print(config["port"])               # 8000

# Безопасное чтение с дефолтом
debug = config.get("debug", False)

Кейс 2: счётчик уникальных посетителей

Сочетание словаря и множества — частый паттерн в аналитике:

logs = [
    ("2024-01-01", "user1"),
    ("2024-01-01", "user2"),
    ("2024-01-01", "user1"),   # повтор user1
    ("2024-01-02", "user3"),
    ("2024-01-02", "user1"),
]

visitors_per_day = {}
for date, user in logs:
    visitors_per_day.setdefault(date, set()).add(user)

for date, users in visitors_per_day.items():
    print(f"{date}: уникальных — {len(users)}")
# 2024-01-01: уникальных — 2
# 2024-01-02: уникальных — 2

Типичные ошибки

1. KeyError на несуществующем ключе

user = {"name": "Анна"}
# print(user["email"])   # KeyError
print(user.get("email"))  # None — безопасно

2. Список как ключ словаря

# d = {[1, 2]: "value"}   # TypeError: unhashable type: 'list'
d = {(1, 2): "value"}     # кортеж — можно

3. Путаница {} и set()

empty_dict = {}      # это словарь, не множество!
empty_set = set()    # а вот так — множество

Практика

  1. Создайте словарь с данными о книге (title, author, year). Выведите значение по ключу author.
  2. Посчитайте частоту каждого символа в строке "hello world" через словарь.
  3. Даны два списка: ключи и значения. Соберите из них словарь через zip().
  4. Найдите пересечение и объединение двух множеств {1,2,3} и {3,4,5}.
  5. Инвертируйте словарь {"a": 1, "b": 2, "c": 3} через dict comprehension.

Итог

Словарь — главная структура для пар «ключ-значение», а множество — для уникальных элементов и быстрых проверок принадлежности. Мы разобрали методы, comprehensions, безопасный доступ через get(), счётчики, setdefault(), склейку списков через zip() и операторы над множествами. В следующей главе научимся группировать код в функции.

Комментарии 0

Для добавления комментариев необходимо войти или зарегистрироваться.

Пока нет комментариев. Станьте первым!