""" Урок 40. Модуль collections — весь код примеров одним файлом. Источник: subjects/python-fundamentals/course/lessons/40-collections-module/examples.html Файл собран автоматически (tools/build_lesson_examples.py): правьте страницу урока. Запуск: python lesson-40.py """ # ==================================================================== # Пример 1. Измерение времени выполнения кода # ==================================================================== # measure_time.py import time start = time.time() values = list(range(1000)) end = time.time() print(len(values)) # 1000 print((end - start) >= 0) # True t0 = time.perf_counter() total = sum(range(100000)) t1 = time.perf_counter() print(total) # 4999950000 print((t1 - t0) >= 0) # True # ==================================================================== # Пример 2. OrderedDict: порядок и move_to_end() # ==================================================================== # ordered_dict_basics.py from collections import OrderedDict queue = OrderedDict() queue["first"] = 1 queue["second"] = 2 queue["third"] = 3 print(queue) # OrderedDict([('first', 1), ('second', 2), ('third', 3)]) print(queue.popitem(last=False)) # ('first', 1) — удалили самый первый print(queue) # OrderedDict([('second', 2), ('third', 3)]) od = OrderedDict({"a": 1, "b": 2, "c": 3}) od.move_to_end("a") print(od) # OrderedDict([('b', 2), ('c', 3), ('a', 1)]) od.move_to_end("c", last=False) print(od) # OrderedDict([('c', 3), ('b', 2), ('a', 1)]) # ==================================================================== # Пример 3. Обычный dict тоже хранит порядок вставки # ==================================================================== # dict_order_vs_ordereddict.py from collections import OrderedDict d1 = {"first": 1, "second": 2} d2 = {"second": 2, "first": 1} print(d1 == d2) # True — обычный dict сравнивает без учёта порядка print(list(d1) == list(d2)) # False — порядок ключей разный print(OrderedDict(d1) == OrderedDict(d2)) # False — OrderedDict сравнивает и порядок тоже # ==================================================================== # Пример 4. functools.lru_cache: кэш вызовов функции # ==================================================================== # lru_cache_basics.py from functools import lru_cache @lru_cache(maxsize=2) def compute_square(number): print(f"compute {number}") return number * number print(compute_square(2)) # compute 2 \n 4 print(compute_square(2)) # 4 — без "compute 2", результат взят из кэша print(compute_square(3)) # compute 3 \n 9 print(compute_square.cache_info()) # CacheInfo(hits=1, misses=2, maxsize=2, currsize=2) print(compute_square(4)) # compute 4 \n 16 — вытеснил самый старый результат (2) print(compute_square.cache_info()) # CacheInfo(hits=1, misses=3, maxsize=2, currsize=2) # ==================================================================== # Пример 5. defaultdict: группировка и подсчёт без проверок # ==================================================================== # defaultdict_grouping.py from collections import defaultdict students = [("Иван", "Физика"), ("Мария", "Математика"), ("Пётр", "Физика")] result = defaultdict(list) for name, faculty in students: result[faculty].append(name) print(dict(result)) # {'Физика': ['Иван', 'Пётр'], 'Математика': ['Мария']} counts = defaultdict(int) for _, faculty in students: counts[faculty] += 1 print(dict(counts)) # {'Физика': 2, 'Математика': 1} # ==================================================================== # Пример 6. Ловушка: defaultdict создаёт ключ уже при чтении # ==================================================================== # defaultdict_mutates_on_read.py from collections import defaultdict dd = defaultdict(list) print(dd.get("missing", [])) # [] print(dict(dd)) # {} — get() не создал ключ print(dd["missing"]) # [] print(dict(dd)) # {'missing': []} — а [] создал! # ==================================================================== # Пример 7. Counter: частотный анализ текста # ==================================================================== # counter_word_frequency.py from collections import Counter text = "This is a test. This test is only a test." words = text.lower().replace(".", "").replace(",", "").split() word_count = Counter(words) print(dict(word_count)) # {'this': 2, 'is': 2, 'a': 2, 'test': 3, 'only': 1} print(word_count.most_common(2)) # [('test', 3), ('this', 2)] # ==================================================================== # Пример 8. Counter: update(), subtract(), elements() и арифметика # ==================================================================== # counter_arithmetic.py from collections import Counter c1 = Counter("banana") print(c1) # Counter({'a': 3, 'n': 2, 'b': 1}) c1.update("nan") print(c1) # Counter({'a': 4, 'n': 4, 'b': 1}) c2 = Counter(a=3, b=1) c3 = Counter(a=1, b=2) print(c2 + c3) # Counter({'a': 4, 'b': 3}) print(c2 - c3) # Counter({'a': 2}) — b получился бы -1, оператор его отбросил print(list((c2 - c3).elements())) # ['a', 'a'] c2.subtract(c3) print(c2) # Counter({'a': 2, 'b': -1}) — subtract() отрицательные значения сохраняет # ==================================================================== # Пример 9. Очередь задач по приоритету на OrderedDict # ==================================================================== # priority_queue.py from collections import OrderedDict tasks = OrderedDict({ "task1": "low priority", "task2": "medium priority", "task3": "low priority", "task4": "high priority", }) for key, value in list(tasks.items()): if "low" in value: tasks.move_to_end(key) if "high" in value: tasks.move_to_end(key, last=False) print(tasks) # OrderedDict([('task4', 'high priority'), ('task2', 'medium priority'), # ('task1', 'low priority'), ('task3', 'low priority')]) # ==================================================================== # Пример 10. Ограничения на практике: нехешируемый Counter и фабрика-функция для defaultdict # ==================================================================== # practical_limits.py from collections import Counter, defaultdict try: bad_counter = Counter([["a"], ["b"]]) except TypeError as error: print("TypeError:", error) # unhashable type: 'list' def default_score(): return {"wins": 0, "losses": 0} scoreboard = defaultdict(default_score) scoreboard["alice"]["wins"] += 1 scoreboard["bob"]["losses"] += 1 scoreboard["alice"]["wins"] += 1 print(dict(scoreboard)) # {'alice': {'wins': 2, 'losses': 0}, 'bob': {'wins': 0, 'losses': 1}}