edubun
Русский

Словари

Обращение к отсутствующему ключу словаря останавливает программу с KeyError, а d.get(key, 0) вместо этого возвращает 0.

У Соён 12 бюллетеней и три кандидата

КонтекстСоён, вымышленная ученица, считает голоса на выборах старосты. Выдвинулись трое одноклассников: Ari, Bo и Cy. В коробке лежат двенадцать сложенных бюллетеней. На бумаге она записала бы три имени сбоку и ставила отметку рядом с именем при открытии каждого бюллетеня. Она хочет сделать то же в Python и быстро замечает, что список неудобен. В нём пришлось бы помнить, что позиция 0 означает Ari, а позиция 1 означает Bo. Ей нужна таблица, где по имени сразу находится число.

Такая таблица называется словарём. В словаре хранятся пары: ключ и соответствующее ему значение. Их записывают в фигурных скобках, ставя двоеточие между каждым ключом и значением. Для чтения значения ключ помещают в квадратные скобки, как индекс после списка. Для добавления или изменения пары используют присваивание по ключу.

votes = {"Ari": 0, "Bo": 0, "Cy": 0}
votes["Bo"] = votes["Bo"] + 1
votes["Ari"] += 1
votes["Bo"] += 1
print(votes)
print(votes["Bo"])
Вывод
{'Ari': 1, 'Bo': 2, 'Cy': 0}
2
Словарь сопоставляет каждому ключу одно значение. votes["Bo"] сразу даёт 5, без отсчёта позиций.

Подсчёт всех бюллетеней одним циклом

Писать по строке на каждый бюллетень не лучше отметок на бумаге. Соён помещает бюллетени в список и обходит его циклом. Возникает трудность: что, если в бюллетене имя, которое она не предусмотрела, или если ей не хочется заранее перечислять кандидатов? Чтение отсутствующего ключа в квадратных скобках останавливает программу. Метод get(key, default) решает проблему: возвращает значение, если ключ есть, и значение по умолчанию, если его нет. Поэтому votes.get(name, 0) + 1 работает и для первого голоса, и для всех последующих.

ballots = ["Bo", "Ari", "Bo", "Cy", "Bo", "Ari",
           "Cy", "Bo", "Ari", "Bo", "Cy", "Bo"]
votes = {}
for name in ballots:
    votes[name] = votes.get(name, 0) + 1
print(votes)
print(len(ballots), sum(votes.values()))
Вывод
{'Bo': 6, 'Ari': 3, 'Cy': 3}
12 12

Последняя строка нужна Соён для проверки. Было двенадцать бюллетеней, сумма счётчиков тоже равна двенадцати, значит, ни один не потерян. Обрати внимание на порядок имён в выводе: Bo идёт первым, ведь это имя первым встретилось циклу. Начиная с Python 3.7 словарь сохраняет порядок первоначального добавления ключей; это же сказано в разделе учебника о словарях.

Обход ключей и значений вместе

Цикл for по словарю даёт ключи. items() даёт ключ и значение вместе, что удобно для таблицы результатов. in проверяет наличие ключа, а max() с key=votes.get находит ключ с наибольшим значением. Последний приём стоит пока копировать целиком, даже если ещё не понятна каждая его часть.

votes = {"Bo": 6, "Ari": 3, "Cy": 3}
for name, n in votes.items():
    print(name, "#" * n, n)
print("Dan" in votes)
print(max(votes, key=votes.get))
Вывод
Bo ###### 6
Ari ### 3
Cy ### 3
False
Bo

Словари встречаются везде, где данные представлены парами имени и значения: слово и его смысл, станция метро и номер линии, номер ученика и имя. Ключи должны быть уникальны; присваивание по существующему ключу заменяет прежнее значение, а не добавляет вторую копию.

словарьПары ключ: значение в { }
ключИмя для поиска значения; ключи уникальны
d[key]Читает значение; KeyError, если ключа нет
d.get(key, default)Читает значение или возвращает значение по умолчанию, если ключа нет
d.items()Пары ключей и значений для цикла for
key in dTrue, если в словаре есть этот ключ
  1. Что выведет этот код?
    price = {"gimbap": 3500, "ramen": 4500}
    print(price["ramen"])
  2. Что выведет этот код?
    price = {"gimbap": 3500}
    price["tteokbokki"] = 5000
    print(len(price))
  3. Что выведет этот код?
    price = {"gimbap": 3500}
    price["gimbap"] = 4000
    print(price)
  4. Что выведет этот код?
    stock = {"pens": 4}
    print(stock.get("pens", 0), stock.get("tape", 0))
  5. Что произойдёт при запуске этого кода?
    stock = {"pens": 4}
    print(stock["tape"])
    • Выведет 0
    • Выведет None
    • Выведет tape
    • Остановится с KeyError: 'tape'
  6. Что выведет этот код?
    counts = {}
    for ch in "hello":
        counts[ch] = counts.get(ch, 0) + 1
    print(counts["l"])
  7. Что выведет этот код?
    ages = {"Mina": 14, "Jun": 13}
    print("Jun" in ages, 14 in ages)
  8. Что выведет этот код?
    d = {"b": 2, "a": 1}
    for k in d:
        print(k)
    • a
      b
    • b
      a
    • 2
      1
    • b 2
      a 1
  9. Что выведет этот код?
    scores = {"Ari": 3, "Bo": 6, "Cy": 3}
    print(max(scores, key=scores.get))
  10. Что выведет этот код?
    d = {"x": 1, "y": 2}
    total = 0
    for k, v in d.items():
        total += v
    print(total)
Частые ошибки
  • «votes["Dan"] даёт 0, если за Dan не проголосовали». Если ключ "Dan" никогда не добавлялся, поиск остановится с KeyError: 'Dan'. Используй votes.get("Dan", 0), когда ключ может отсутствовать.
  • «14 in ages проверяет, есть ли кому-нибудь 14 лет». in проверяет ключи, а не значения. Для поиска среди значений напиши 14 in ages.values().
  • «У словаря есть позиции, как у списка, поэтому votes[0] даёт первого кандидата». В словаре ищут по ключу, а не по позиции. votes[0] ищет ключ, равный 0, и выдаёт KeyError: 0.
Заметка для учителяНачни с отметок на бумаге. Сначала посчитайте вручную небольшой набор настоящих или вымышленных голосов, затем покажи, что словарь представляет ту же таблицу: слева имя, справа количество. Строку get(key, 0) + 1 стоит запомнить целиком: подсчёт — самое частое применение словарей в первых проектах. Привычку сверять сумму счётчиков с числом бюллетеней тоже стоит заложить сразу. В корейской старшей школе выбор подходящего типа данных выделен в отдельный стандарт информатики; сравнение словаря со списком ему соответствует.
Главное
  • Словарь хранит пары ключ: значение в { }.
  • d[key] читает значение; отсутствующий ключ вызывает KeyError.
  • d.get(key, default) позволяет избежать KeyError.
  • counts[x] = counts.get(x, 0) + 1 используется для подсчёта.
  • for k, v in d.items(): обходит пары в порядке добавления.
Источники курса (6)
  • Python Software Foundation, The Python Tutorial for Python 3.12 (docs.python.org/3.12/tutorial: 2 Using the Python Interpreter, 3 An Informal Introduction to Python (numbers, text, lists), 4 More Control Flow Tools (if, for, range, break and continue, defining functions, default argument values, 4.10 coding style: 4-space indentation), 5 Data Structures (list methods, 5.5 dictionaries, insertion order), 8 Errors and Exceptions (syntax errors, exceptions, reading the traceback, handling exceptions), 15 Floating-Point Arithmetic (0.1 + 0.2))
  • Built-in Functions (docs.python.org/3.12/library/functions.html: print, input, len, int, float, str, type, round (round half to even: round(0.5) and round(-0.5) are 0, round(1.5) is 2), range, sum, min, max, sorted)
  • Built-in Types (str methods upper, lower, replace, strip; dict.get; list.append, pop, remove, sort returning None)
  • General Python FAQ (docs.python.org/3.12/faq/general.html: Guido van Rossum began Python in the 1989 Christmas holidays, posted it to USENET in February 1991, named it after Monty Python's Flying Circus)
  • Curriculum for the Korean pages: 교육부 고시 제2022-33호 [별책 10] 정보과 교육과정 (PDF read 2026-10-19: 중학교 정보 [9정03-05] 리스트 등 데이터를 순차적으로 저장하는 구조, [9정03-06] 논리 연산과 중첩 제어 구조, [9정03-07] 함수 활용과 디버거로 오류 수정, [9정03-08] 실생활 문제를 프로그래밍으로 해결, 적용 시 고려 사항 「학생의 수준을 고려하여 적합한 프로그래밍 언어를 선정」; 고등학교 정보 [12정03-04] 자료형, [12정03-05] 표준입출력, [12정03-07] 제어 구조)
  • Bug story only: Smithsonian National Museum of American History, Log Book With Computer Bug, 1947, Harvard Mark II, "first actual case of bug being found", probably not Hopper's log book (americanhistory.si.edu/collections/object/nmah_334663, read 2026-10-19)

Проверено: 2026-10-19