Python для начинающих
1.24K subscribers
546 photos
3 videos
232 files
74 links
Python для начинающих
Download Telegram
Как использовать модуль time для измерения скорости выполнения
Как использовать модуль time для измерения скорости выполнения кода

Когда код начинает тормозить, первым делом нужно ответить на простой вопрос: что именно работает медленно? Для этого не нужен сложный профайлер — в большинстве случаев хватит стандартного модуля time.

---

### 1. Быстрое измерение через time.time()

Функция time.time() возвращает текущее время в секундах с начала эпохи (обычно 1 января 1970). Если замерить время до и после участка кода — получим длительность его выполнения.

import time

def slow_operation():
total = 0
for i in range(10_000_000):
total += i
return total

start = time.time()
result = slow_operation()
end = time.time()

elapsed = end - start
print(f"Result: {result}")
print(f"Elapsed: {elapsed:.4f} seconds")


Плюс: просто и понятно.
Минус: точность зависит от системы, и эта функция не гарантирует высокую разрешающую способность.

---

### 2. Более точный замер через time.perf_counter()

time.perf_counter() специально создан для измерения интервалов времени. Он не привязан к "реальному" времени, зато максимально точен и не страдает от смены системных часов.

import time

def fast_operation():
return sum(range(10_000_000))

start = time.perf_counter()
result = fast_operation()
end = time.perf_counter()

elapsed = end - start
print(f"Result: {result}")
print(f"Elapsed: {elapsed:.6f} seconds")


Используйте perf_counter() во всех случаях, когда вас интересует скорость кода, а не текущее время.

---

### 3. Сравниваем два варианта решения

Предположим, мы хотим понять, что быстрее: цикл или встроенная функция sum.

import time

def sum_loop(n):
total = 0
for i in range(n):
total += i
return total

def sum_builtin(n):
return sum(range(n))

def measure(func, n, repeats=5):
best = float("inf")
for _ in range(repeats):
start = time.perf_counter()
func(n)
end = time.perf_counter()
elapsed = end - start
if elapsed < best:
best = elapsed
return best

n = 5_000_000
t_loop = measure(sum_loop, n)
t_builtin = measure(sum_builtin, n)

print(f"Loop: {t_loop:.6f} s")
print(f"Builtin: {t_builtin:.6f} s")


Здесь мы запускаем каждую функцию несколько раз и берём лучший результат — так меньше влияние случайных задержек (нагрузка системы, кэш, фоновые процессы).

---

### Вывод

Модуль time — это простой, но мощный инструмент, чтобы:
- измерять скорость отдельных участков кода;
- сравнивать разные реализации;
- находить узкие места без сложных инструментов.

Запомните правило:
time.time() — для "какой сейчас час", time.perf_counter() — для "как быстро это работает".
🔥2
Редактирование изображений с помощью библиотеки pillow (PIL)
### Редактирование изображений с помощью Pillow: первые шаги в «фотошопе на Python»

Pillow — это библиотека, которая превращает Python в мини-фотошоп: можно обрезать, сжимать, накладывать текст, применять фильтры и даже собирать простые превьюшки для соцсетей.

Устанавливается просто:

pip install pillow


Базовый импорт:

from PIL import Image, ImageFilter, ImageEnhance, ImageFont, ImageDraw


---

### Открытие и сохранение изображений

from PIL import Image

img = Image.open("input.jpg") # открываем
print(img.size, img.mode, img.format)

resized = img.resize((800, 600)) # изменение размеров
resized.save("output_resized.jpg", quality=85)


quality=85 полезно для оптимизации картинок под веб.

---

### Обрезка и поворот

img = Image.open("input.jpg")

# crop(left, upper, right, lower)
cropped = img.crop((100, 100, 600, 600))
rotated = cropped.rotate(30, expand=True)

rotated.save("output_cropped_rotated.png")


expand=True не обрежет картинку после поворота.

---

### Фильтры и улучшение качества

from PIL import Image, ImageFilter, ImageEnhance

img = Image.open("input.jpg")

blurred = img.filter(ImageFilter.GaussianBlur(radius=2))
sharpener = ImageEnhance.Sharpness(blurred)
sharpened = sharpener.enhance(1.8) # 1.0 — без изменений

contrast = ImageEnhance.Contrast(sharpened).enhance(1.3)

contrast.save("output_filtered.jpg")


Так можно быстро «подтянуть» резкость и контраст фото.

---

### Нанесение текста (водяной знак)

from PIL import Image, ImageDraw, ImageFont

img = Image.open("input.jpg").convert("RGBA")
txt_layer = Image.new("RGBA", img.size, (0, 0, 0, 0))

draw = ImageDraw.Draw(txt_layer)
font = ImageFont.truetype("arial.ttf", 40)

text = "myblog.dev"
text_pos = (img.size[0] - 250, img.size[1] - 60)

draw.text(text_pos, text, font=font, fill=(255, 255, 255, 120))

watermarked = Image.alpha_composite(img, txt_layer)
watermarked.convert("RGB").save("output_watermarked.jpg")


Здесь создается прозрачный слой, на который рисуется полупрозрачный текст, а затем он накладывается на оригинал.

---

### Массовая обработка изображений

import pathlib
from PIL import Image

input_dir = pathlib.Path("photos")
output_dir = pathlib.Path("photos_optimized")
output_dir.mkdir(exist_ok=True)

for path in input_dir.glob("*.jpg"):
img = Image.open(path)
img.thumbnail((1200, 1200))
img.save(output_dir / path.name, quality=80, optimize=True)


Этот скрипт автоматически уменьшит и сожмет все фото в папке — полезно перед загрузкой на сайт.

---

Pillow хорош тем, что порог входа низкий: уже через пару десятков строк кода можно автоматизировать то, что обычно делается руками в графическом редакторе. А дальше — фильтры, коллажи, генерация превью, мемы и целые пайплайны обработки изображений.
👍2
Мониторинг системных ресурсов с использованием psutil
Мониторинг системных ресурсов с помощью psutil: делаем свой мини‑«Диспетчер задач»

Если вы когда‑нибудь задумывались, как Python‑скрипт может узнать, сколько у вас свободной памяти, насколько загружен процессор и кто вообще ест весь диск — вам нужен модуль psutil.

psutil (process and system utilities) — кроссплатформенная библиотека для работы с системной статистикой: CPU, память, диски, сеть, процессы. Идеален для небольших утилит мониторинга и первых шагов в сторону системного администрирования на Python.

---

### Установка

pip install psutil


---

### Базовый мониторинг CPU и памяти

import psutil
import time

def print_basic_stats():
cpu = psutil.cpu_percent(interval=1)
mem = psutil.virtual_memory()
print(f"CPU: {cpu}%")
print(f"Memory: {mem.percent}% used ({mem.used // (1024**2)} MB / {mem.total // (1024**2)} MB)")

if __name__ == "__main__":
while True:
print_basic_stats()
time.sleep(2)


Здесь:
- cpu_percent(interval=1) замеряет загрузку за последнюю секунду;
- virtual_memory() возвращает объект с подробной статистикой по ОЗУ.

---

### Мониторинг диска и сети

import psutil
import time

def print_disk_and_net():
disk = psutil.disk_usage("/")
net1 = psutil.net_io_counters()
time.sleep(1)
net2 = psutil.net_io_counters()

sent_speed = (net2.bytes_sent - net1.bytes_sent) / 1024
recv_speed = (net2.bytes_recv - net1.bytes_recv) / 1024

print(f"Disk used: {disk.percent}%")
print(f"Net: ↑ {sent_speed:.1f} KB/s, ↓ {recv_speed:.1f} KB/s")

if __name__ == "__main__":
while True:
print_disk_and_net()


Так можно быстро понять, нагружает ли диск какой‑то процесс и есть ли сетевой трафик.

---

### Кто все это ест: процессы

import psutil

def top_memory_processes(limit=5):
processes = []
for proc in psutil.process_iter(["pid", "name", "memory_percent"]):
processes.append(proc.info)
processes.sort(key=lambda p: p["memory_percent"], reverse=True)
for p in processes[:limit]:
print(f"{p['pid']:>6} {p['memory_percent']:5.1f}% {p['name']}")

if __name__ == "__main__":
top_memory_processes()


Функция показывает топ процессов по использованию памяти — уже что‑то вроде урезанного списка в «Диспетчере задач».

---

psutil позволяет вам из простого скрипта превратиться в маленький системный «радист»: собирать метрики, логировать их, строить графики, реагировать на перегрузки. Для начинающего питониста это отличный модуль, чтобы почувствовать, что ваш код взаимодействует не только с текстовыми задачками, но и с «живой» системой.
🔥2
Простое создание ZIP-архивов с zipfile и shutil
### Простое создание ZIP-архивов с zipfile и shutil

Архивация — одна из тех задач, которые рано или поздно понадобятся почти в любом проекте: сделать бэкап, запаковать логи, отправить результаты работы скрипта. В Python это можно сделать «вручную» с модулем zipfile, а можно — «по-быстрому» с shutil. Разберём оба подхода.

---

## Вариант 1: полный контроль с zipfile

zipfile даёт гибкость: можно выбирать режимы сжатия, добавлять отдельные файлы и целые папки, читать содержимое архива.

### Создание архива и добавление файлов

import zipfile
from pathlib import Path

base_dir = Path("project_data")
zip_path = Path("backup.zip")

with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
for file_path in base_dir.rglob("*"):
if file_path.is_file():
arc_name = file_path.relative_to(base_dir)
zf.write(file_path, arcname=arc_name)

print(f"Created archive: {zip_path}")


Что тут важно:

- mode="w" — создать новый архив (перезапишет существующий).
- ZIP_DEFLATED — стандартное сжатие.
- relative_to(base_dir) — в архив не попадут «лишние» абсолютные пути.

### Просмотр содержимого архива

import zipfile

with zipfile.ZipFile("backup.zip", "r") as zf:
print(zf.namelist())


Можно и читать файлы напрямую, не распаковывая всё:

with zipfile.ZipFile("backup.zip", "r") as zf:
with zf.open("subdir/report.txt") as f:
content = f.read().decode("utf-8")
print(content)


---

## Вариант 2: быстро и просто с shutil

Если нужен просто «запаковать папку целиком» — shutil.make_archive делает это одной строкой.

import shutil
from pathlib import Path

base_dir = Path("project_data")

archive_path = shutil.make_archive(
base_name="project_backup", # будет project_backup.zip
format="zip",
root_dir=base_dir
)

print(f"Archive created at: {archive_path}")


Можно так же легко создавать не только ZIP, но и tar, gztar, bztar.

---

## Когда что использовать?

- zipfile — когда нужен контроль: выбор файлов, чтение из архива, выбор метода сжатия, обновление существующего архива.
- shutil — когда задача проста: «возьми эту папку и сделай из неё ZIP».

Оба модуля входят в стандартную библиотеку, так что никаких дополнительных установок — просто импортируйте и архивируйте.
👍1
Как класть и извлекать данные из стека и очереди: deque из collections
Как класть и извлекать данные из стека и очереди: deque из collections

Если вам нужны стек или очередь в Python, не спешите писать свои классы. В стандартной библиотеке уже есть мощный инструмент — collections.deque. Это двусторонняя очередь, но из неё легко сделать и стек, и обычную очередь.

---

## Быстрый старт

from collections import deque

dq = deque() # пустая deque
dq = deque([1, 2, 3]) # инициализация с данными


deque оптимизирован под операции добавления/удаления с обоих концов — в отличие от обычного списка, где pop(0) и insert(0, x) работают медленно.

---

## deque как стек (LIFO)

Стек — это принцип “последним пришёл — первым вышел” (LIFO). Для стека нам нужны две операции: положить и достать с одного и того же конца.

from collections import deque

stack = deque()

# кладём в стек
stack.append("page_1")
stack.append("page_2")
stack.append("page_3")

# достаём из стека
last_page = stack.pop() # "page_3"
prev_page = stack.pop() # "page_2"


Здесь append() и pop() работают с “хвостом” очереди. Именно так строится история переходов в браузере, отмена действий в редакторе и т.п.

---

## deque как очередь (FIFO)

Очередь — “первым пришёл — первым вышел” (FIFO). Добавляем в конец, забираем из начала.

from collections import deque

queue = deque()

# приходят задачи
queue.append("task_1")
queue.append("task_2")
queue.append("task_3")

# обрабатываем в порядке поступления
first = queue.popleft() # "task_1"
second = queue.popleft() # "task_2"


Ключевой метод — popleft(): быстро забирает элемент с начала. Для списка аналог pop(0) был бы заметно медленнее.

---

## Двусторонняя очередь

Иногда удобно, что deque — двусторонняя:

from collections import deque

dq = deque([2, 3])

dq.appendleft(1) # слева: [1, 2, 3]
dq.append(4) # справа: [1, 2, 3, 4]

left = dq.popleft() # 1
right = dq.pop() # 4


Так можно, например, реализовать “слайдящуюся” историю последних N элементов.

---

## Ограниченный размер: maxlen

deque умеет автоматически забывать старые элементы:

from collections import deque

history = deque(maxlen=3)

for i in range(5):
history.append(i)

print(history) # deque([2, 3, 4], maxlen=3)


Полезно для логов, последних измерений, кэшей.

---

Главное: запомните четыре метода — append, appendleft, pop, popleft. С их помощью вы можете построить стек, очередь и даже более сложные структуры, не выходя за рамки стандартной библиотеки Python.
👍2
Создание CLI-интерфейсов с библиотекой argparse
Python для начинающих: создаём удобные CLI-интерфейсы с argparse

Большинство утилит в терминале — это просто программы с аргументами командной строки. python script.py --input data.txt --verbose выглядит профессионально и удобно. За этим стоит стандартная библиотека argparse, которую многие новички игнорируют, а зря.

### Минимальный пример

Начнём с простого: создадим скрипт, который приветствует пользователя.

import argparse

def main():
parser = argparse.ArgumentParser(
description="Simple greeting script"
)
parser.add_argument(
"name",
help="User name to greet"
)
parser.add_argument(
"-t", "--times",
type=int,
default=1,
help="How many times to print greeting"
)

args = parser.parse_args()

for _ in range(args.times):
print(f"Hello, {args.name}!")

if __name__ == "__main__":
main()


Теперь в терминале:

python greet.py Alice
python greet.py Alice --times 3


argparse сам:
- парсит аргументы,
- проверяет типы (type=int),
- подставляет значения по умолчанию (default=1),
- показывает аккуратную справку: python greet.py -h.

### Флаги и режимы работы

Добавим флаг, который ничего не принимает, но меняет поведение:

import argparse

def main():
parser = argparse.ArgumentParser(
description="File size checker"
)
parser.add_argument("path", help="Path to file")
parser.add_argument(
"-q", "--quiet",
action="store_true",
help="Print only raw size in bytes"
)

args = parser.parse_args()

import os
size = os.path.getsize(args.path)

if args.quiet:
print(size)
else:
print(f"File: {args.path}")
print(f"Size: {size} bytes")

if __name__ == "__main__":
main()


Ключевой момент — action="store_true": если флаг указан, в args.quiet будет True, иначе False.

### Подкоманды: как git clone, git status

Аргументы можно группировать в подкоманды:

import argparse

def cmd_add(args):
print(args.x + args.y)

def cmd_mul(args):
print(args.x * args.y)

def main():
parser = argparse.ArgumentParser(
description="Simple calculator"
)
subparsers = parser.add_subparsers(
dest="command",
required=True
)

parser_add = subparsers.add_parser("add", help="Add numbers")
parser_add.add_argument("x", type=int)
parser_add.add_argument("y", type=int)
parser_add.set_defaults(func=cmd_add)

parser_mul = subparsers.add_parser("mul", help="Multiply numbers")
parser_mul.add_argument("x", type=int)
parser_mul.add_argument("y", type=int)
parser_mul.set_defaults(func=cmd_mul)

args = parser.parse_args()
args.func(args)

if __name__ == "__main__":
main()


Теперь:

python calc.py add 2 3   # 5
python calc.py mul 2 3 # 6


Так строятся целые консольные инструменты: один файл — множество команд.

### Почему стоит привыкнуть к argparse

- Встроен в стандартную библиотеку, без лишних зависимостей.
- Автоматически генерирует --help.
- Делает интерфейс предсказуемым и профессиональным.
- Легко расширяется: типы, значения по умолчанию, подкоманды, обязательные/необязательные аргументы.

Один раз освоив argparse, вы перестаёте писать input() в каждом втором скрипте и начинаете создавать настоящие консольные утилиты. Это маленький шаг в коде, но большой шаг к тому, чтобы ваши программы выглядели как «настоящие инструменты», а не учебные примеры.
🔥31
Преобразование строк и чисел с помощью форматирования f-строк
Преобразование строк и чисел с помощью форматирования f-строк

Если вы все еще конкатенируете строки через +, самое время остановиться. В Python есть более мощный и удобный инструмент — f-строки (formatted string literals). Они не только делают код читаемее, но и позволяют красиво преобразовывать числа и строки буквально “на лету”.

---

### Базовый синтаксис

F-строка — это строка с буквой f перед кавычками. Внутри фигурных скобок {} можно писать выражения:

name = "Alice"
age = 25
text = f"Name: {name}, age: {age}"
print(text) # Name: Alice, age: 25


Уже лучше, чем "Name: " + name + ", age: " + str(age).

---

### Форматирование чисел

Главная магия начинается, когда нужно красиво отобразить числа.

Количество знаков после запятой:

price = 12.34567
print(f"{price:.2f}") # 12.35
print(f"{price:.0f}") # 12


.2f — два знака после запятой, .0f — без дробной части.

Разделение разрядов:

big_num = 1234567890
print(f"{big_num:,}") # 1,234,567,890
print(f"{big_num:_}") # 1_234_567_890


Запятая или нижнее подчеркивание помогают “читать” большие числа.

Проценты:

ratio = 0.0789
print(f"{ratio:.2%}") # 7.89%


---

### Выравнивание и ширина

Можно управлять тем, как текст и числа “лежат” в строке — удобно для табличного вывода.

items = [("Apple", 3.5), ("Banana", 12.0), ("Kiwi", 0.95)]

for name, price in items:
print(f"{name:<10} | {price:>7.2f}")


- <10 — выравнивание по левому краю, ширина 10 символов
- >7.2f — по правому краю, ширина 7, два знака после запятой

Вывод будет аккуратно выровнен по столбцам.

---

### Форматирование чисел в разных системах счисления

num = 42
print(f"bin: {num:b}") # bin: 101010
print(f"hex: {num:x}") # hex: 2a
print(f"HEX: {num:#X}") # HEX: 0X2A


# добавляет префикс 0b, 0x, 0o.

---

### Вложенные выражения и функции

В f-строках можно вызывать функции и писать выражения:

import math

x = 2
print(f"sqrt({x}) = {math.sqrt(x):.3f}")
print(f"{x}! = {math.factorial(x)}")


---

### Быстрая диагностика: =

С Python 3.8 появилось удобство для отладки: =

a = 7
b = 3
print(f"{a=}, {b=}, sum={a + b}")
# a=7, b=3, sum=10


---

F-строки — это компактный, выразительный и очень мощный способ преобразовывать и форматировать строки и числа. Освоив их, вы заметите, насколько чище и понятнее станет ваш код.
👍6
Создание таплов и однострочных функций с помощью lambda и map
Создание таплов и однострочных функций с помощью lambda и map

Python любит, когда код короткий и понятный. Сегодня разберём связку, которая идеально подходит для “быстрых” преобразований данных: lambda + map + кортежи (tuples).

---

### 1. Что такое lambda и зачем она нужна

lambda — это способ создать функцию “на лету”, прямо внутри выражения, без def и имени.

Обычная функция:

def square(x):
return x ** 2


То же самое с lambda:

square = lambda x: x ** 2


А можно вообще не присваивать её переменной, а использовать сразу в выражении — и вот тут в игру вступает map.

---

### 2. map: применяем функцию ко всем элементам

map(func, iterable) берёт каждый элемент из iterable и прогоняет его через func.
Типичный пример:

nums = [1, 2, 3, 4]
result = map(lambda x: x * 10, nums)
print(list(result)) # [10, 20, 30, 40]


Обрати внимание: map возвращает итератор, поэтому часто его оборачивают в list() или tuple().

---

### 3. Создаём таплы с помощью map и lambda

Допустим, у нас есть список чисел, и мы хотим получить кортеж пар (число, его квадрат):

nums = [1, 2, 3, 4, 5]

pairs = tuple(
map(lambda x: (x, x ** 2), nums)
)

print(pairs)
# ((1, 1), (2, 4), (3, 9), (4, 16), (5, 25))


Здесь важно:

- lambda x: (x, x ** 2) возвращает кортеж из двух элементов.
- map(...) создаёт поток таких кортежей.
- tuple(...) собирает их в один большой кортеж.

---

### 4. Комбинируем несколько итерируемых объектов

map может работать сразу с несколькими последовательностями. Например, создадим кортеж таплов из координат:

xs = [0, 1, 2]
ys = [10, 11, 12]

points = tuple(
map(lambda x, y: (x, y), xs, ys)
)

print(points)
# ((0, 10), (1, 11), (2, 12))


Так можно элегантно “склеивать” данные без явных циклов.

---

### 5. Однострочные конвейеры преобразований

Связка map + lambda хорошо работает как мини-конвейер обработки данных:

raw_data = ["1", "2", "3", "4"]

processed = tuple(
map(lambda x: int(x) * 2, raw_data)
)

print(processed)
# (2, 4, 6, 8)


Считываем строки → сразу превращаем в числа → сразу умножаем.

---

### Когда это оправдано

- Нужно быстро преобразовать последовательность.
- Логика простая и умещается в одну строку.
- Нужен результат именно в виде кортежей (например, для неизменяемых данных или в качестве ключей словаря).

Если выражение становится громоздким и трудно читаемым — лучше вернуться к обычным функциям и циклам. Но для небольших преобразований lambda + map + tuple даёт лаконичный и выразительный код, который отлично вписывается в стиль Python.
👍2🔥1
Объединение и фильтрация данных с filter, map, zip
Объединение и фильтрация данных с filter, map, zip

Представьте, что у вас есть конвейер обработки данных. Вход — «сырые» списки, выход — аккуратный результат. В Python роль такого конвейера идеально играют функции filter, map и zip. Разберём, как их сочетать так, чтобы код был короче, понятнее и «питонистее».

---

### filter: оставляем только нужное

filter(func, iterable) пропускает через себя элементы, оставляя только те, для которых func возвращает True.

numbers = [10, -3, 0, 25, -7, 8]

def is_positive(x):
return x > 0

positive_numbers = list(filter(is_positive, numbers))
print(positive_numbers) # [10, 25, 8]


То же самое через lambda:

positive_numbers = list(filter(lambda x: x > 0, numbers))


---

### map: трансформируем элементы

map(func, iterable) применяет функцию к каждому элементу.

numbers = [1, 2, 3, 4]

squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16]


Комбинация с filter даёт уже мини-пайплайн:

numbers = [-3, -1, 0, 1, 2, 3]

result = list(
map(
lambda x: x ** 2,
filter(lambda x: x > 0, numbers)
)
)
print(result) # [1, 4, 9]


Сначала отфильтровали положительные, потом возводим их в квадрат.

---

### zip: объединяем несколько источников данных

zip склеивает элементы из нескольких итерируемых объектов по позициям.

names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]

paired = list(zip(names, scores))
print(paired) # [('Alice', 85), ('Bob', 92), ('Charlie', 78)]


На основе zip удобно строить структуры данных:

students = [
{"name": name, "score": score}
for name, score in zip(names, scores)
]
print(students)
# [{'name': 'Alice', 'score': 85}, ...]


---

### Все вместе: мини-аналитика

Допустим, у нас есть имена, оценки и флаг «сдал экзамен» (True/False). Нужно оставить только тех, кто сдал, и взять их имена и удвоенные баллы (например, за бонус).

names = ["Alice", "Bob", "Charlie", "Diana"]
scores = [85, 40, 73, 95]
passed = [True, False, True, True]

data = zip(names, scores, passed)

passed_transformed = list(
map(
lambda item: (item[0], item[1] * 2),
filter(lambda item: item[2], data)
)
)

print(passed_transformed)
# [('Alice', 170), ('Charlie', 146), ('Diana', 190)]


zip объединяет разрозненные списки в единый поток кортежей, filter выбрасывает тех, кто не сдал, map меняет формат результата и пересчитывает баллы.

---

filter, map и zip — это кирпичики для построения аккуратных конвейеров обработки данных. В связке они позволяют писать код, который одновременно лаконичен и легко читается как последовательность шагов над данными.
👍3
Как использовать структуру данных defaultdict для подсчета значений
### Как использовать defaultdict для подсчета значений

Если вы когда‑нибудь считали что‑то с помощью словаря — количество слов, кликов, покупок, — вы наверняка писали что‑то вроде:

counts = {}
for item in items:
if item in counts:
counts[item] += 1
else:
counts[item] = 1


Работает, но выглядит громоздко. В Python есть инструмент, который делает это элегантнее — collections.defaultdict.

---

## Что такое defaultdict

Обычный словарь выбрасывает KeyError, если обратиться к несуществующему ключу.
defaultdict вместо ошибки автоматически создаёт значение по умолчанию.

Импорт:

from collections import defaultdict


Создание:

from collections import defaultdict

counts = defaultdict(int) # int() -> 0


Теперь при первом обращении к counts[key] под капотом создаётся 0, и вы можете сразу увеличивать счётчик:

for item in items:
counts[item] += 1


Никаких if, всё уже есть.

---

## Пример 1: Подсчёт слов в тексте

from collections import defaultdict

text = "banana apple banana orange apple banana"
words = text.split()

word_counts = defaultdict(int)

for word in words:
word_counts[word] += 1

print(dict(word_counts))
# {'banana': 3, 'apple': 2, 'orange': 1}


int как фабрика значений даёт 0 по умолчанию. Увеличиваем — и счётчик растёт.

---

## Пример 2: Группировка значений по ключу

defaultdict полезен не только с числами. Частый сценарий — группировка.

from collections import defaultdict

users = [
("alice", "admin"),
("bob", "user"),
("charlie", "admin"),
("david", "user"),
]

grouped = defaultdict(list)

for name, role in users:
grouped[role].append(name)

print(dict(grouped))
# {'admin': ['alice', 'charlie'], 'user': ['bob', 'david']}


Здесь list() создаёт пустой список при первом доступе, и мы просто делаем .append().

---

## Пример 3: Подсчёт сумм по категориям

from collections import defaultdict

sales = [
("books", 120),
("electronics", 300),
("books", 80),
("games", 150),
]

totals = defaultdict(float)

for category, amount in sales:
totals[category] += amount

print(dict(totals))
# {'books': 200.0, 'electronics': 300.0, 'games': 150.0}


float() даёт 0.0, удобно для денег и чисел с плавающей точкой.

---

## Когда defaultdict особенно полезен

- Подсчёт частот (слов, кликов, событий).
- Группировка данных (пользователи по ролям, товары по категориям).
- Накопление сумм и списков без постоянных проверок if key in dict.

Формула запоминания простая:
“Если я пишу if key in d: ... else: ... — возможно, мне нужен defaultdict.”
👍2