39. Ключевые модули стандартной библиотеки
Стандартная библиотека(standard library) Python — это набор модулей, которые поставляются вместе с Python: вам не нужно устанавливать ничего дополнительно, чтобы ими пользоваться. Эти модули предоставляют мощные инструменты для типичных задач программирования: генерация случайных чисел, работа с датами и временем, обмен данными с другими программами и использование специализированных структур данных, которые выходят за рамки базовых списков и словарей.
В этой главе мы рассмотрим пять ключевых модулей стандартной библиотеки, которые вы будете часто использовать в реальной разработке на Python.
39.1) Генерация случайности с random
Модуль random предоставляет функции для генерации случайных чисел и выполнения случайных выборок. Это полезно для симуляций, игр, тестирования, выборки данных и любых ситуаций, где нужно непредсказуемое поведение.
39.1.1) Генерация случайных целых чисел с randint()
Функция randint() генерирует случайное целое число между двумя значениями, включительно по обоим концам:
import random
# Симуляция броска шестигранного кубика
die_roll = random.randint(1, 6)
print(f"You rolled: {die_roll}") # Output: You rolled: 4 (varies each run)
# Генерация случайного возраста между 18 и 65
age = random.randint(18, 65)
print(f"Random age: {age}") # Output: Random age: 42 (varies)Обратите внимание, что и начальное, и конечное значения включаются в возможные результаты. randint(1, 6) может вернуть 1, 2, 3, 4, 5 или 6 — возможны все шесть значений.
Вот практический пример, который имитирует несколько бросков кубиков:
import random
# Симуляция броска двух кубиков и вычисление их суммы
die1 = random.randint(1, 6)
die2 = random.randint(1, 6)
total = die1 + die2
print(f"Die 1: {die1}") # Output: Die 1: 3 (varies)
print(f"Die 2: {die2}") # Output: Die 2: 5 (varies)
print(f"Total: {total}") # Output: Total: 8 (varies)
if total == 7:
print("Lucky seven!")
elif total == 2 or total == 12:
print("Snake eyes or boxcars!")Почему оба конца включаются: это делает randint() интуитивной для типичных сценариев. Когда вы хотите число от 1 до 6 (как на кубике), вы пишете randint(1, 6), и как 1, так и 6 могут оказаться результатом.
39.1.2) Генерация случайных чисел с плавающей точкой
Для случайных десятичных чисел используйте random() (возвращает float между 0.0 и 1.0) или uniform() (возвращает float между двумя заданными значениями):
import random
# Сгенерировать случайное число с плавающей точкой между 0.0 и 1.0 (0.0 включено, 1.0 исключено)
probability = random.random()
print(f"Random probability: {probability:.4f}") # Output: Random probability: 0.7284 (varies)
# Сгенерировать случайную температуру между 15.0 и 30.0 градусами
temperature = random.uniform(15.0, 30.0)
print(f"Temperature: {temperature:.2f}°C") # Output: Temperature: 23.47°C (varies)
# Сгенерировать случайную цену между $10.00 и $99.99
price = random.uniform(10.0, 99.99)
print(f"Price: ${price:.2f}") # Output: Price: $45.67 (varies)Функция random() полезна, когда вам нужно значение вероятности или процент. Функция uniform() лучше, когда вам нужно случайное десятичное число в конкретном диапазоне.
39.1.3) Случайный выбор с choice()
Функция choice() случайным образом выбирает один элемент из последовательности (список(list), кортеж(tuple) или строка(string)):
import random
# Случайным образом выбрать цвет
colors = ["red", "blue", "green", "yellow", "purple"]
selected_color = random.choice(colors)
print(f"Selected color: {selected_color}") # Output: Selected color: green (varies)
# Случайным образом выбрать победителя среди участников
participants = ["Alice", "Bob", "Charlie", "Diana"]
winner = random.choice(participants)
print(f"The winner is: {winner}") # Output: The winner is: Bob (varies)
# Случайным образом выбрать символ из строки
vowels = "aeiou"
random_vowel = random.choice(vowels)
print(f"Random vowel: {random_vowel}") # Output: Random vowel: i (varies)Это особенно полезно для игр, случайной выборки или выбора случайных тестовых данных. Каждый элемент в последовательности имеет равную вероятность быть выбранным.
Вот более сложный пример, который имитирует простую викторину:
import random
# Вопросы викторины с их ответами
questions = [
("What is 2 + 2?", "4"),
("What is the capital of France?", "Paris"),
("What color is the sky?", "blue")
]
# Случайным образом выбрать вопрос
question, correct_answer = random.choice(questions)
print(f"Question: {question}")
user_answer = input("Your answer: ")
if user_answer.lower() == correct_answer.lower():
print("Correct!")
else:
print(f"Wrong! The answer was: {correct_answer}")39.1.4) Выбор нескольких случайных элементов с sample()
Когда нужно выбрать несколько уникальных элементов из последовательности, используйте sample(). Это похоже на вытягивание карт из колоды без возвращения — как только элемент выбран, он больше не будет выбран снова:
import random
# Выбрать 3 случайных студентов для группового проекта
students = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]
group = random.sample(students, 3)
print(f"Group members: {group}") # Output: Group members: ['Diana', 'Alice', 'Frank'] (varies)
# Вытянуть 5 лотерейных чисел от 1 до 50 (без повторов)
lottery_numbers = random.sample(range(1, 51), 5)
lottery_numbers.sort() # Отсортировать для отображения
print(f"Lottery numbers: {lottery_numbers}") # Output: Lottery numbers: [7, 15, 23, 38, 49] (varies)Второй аргумент sample() задаёт, сколько элементов выбрать. Число должно быть меньше или равно длине последовательности — нельзя выбрать больше элементов, чем доступно.
39.1.5) Перемешивание последовательностей с shuffle()
Функция shuffle() случайным образом переупорядочивает элементы списка(list) на месте (изменяя исходный список):
import random
# Перемешать колоду карт
cards = ["A♠", "K♠", "Q♠", "J♠", "10♠", "9♠", "8♠", "7♠"]
print(f"Original: {cards}")
random.shuffle(cards)
print(f"Shuffled: {cards}") # Output: Shuffled: ['Q♠', '7♠', 'A♠', '10♠', '9♠', 'J♠', 'K♠', '8♠'] (varies)
# Перемешать вопросы викторины для случайного порядка
questions = ["Question 1", "Question 2", "Question 3", "Question 4"]
random.shuffle(questions)
print(f"Randomized order: {questions}") # Output: Randomized order: ['Question 3', 'Question 1', 'Question 4', 'Question 2'] (varies)39.2) Работа с датами и временем
Модуль datetime предоставляет классы для работы с датами, временем и интервалами времени. Это важно для планирования, логирования, расчёта длительностей и любых приложений, которым нужно отслеживать, когда происходят события.
39.2.1) Получение текущих даты и времени
Класс datetime представляет конкретный момент времени, включающий и дату, и время:
from datetime import datetime
# Получить текущие дату и время
now = datetime.now()
print(f"Current datetime: {now}")
# Output: Current datetime: 2026-01-02 14:30:45.123456
# Доступ к отдельным компонентам
print(f"Year: {now.year}") # Output: Year: 2026
print(f"Month: {now.month}") # Output: Month: 1
print(f"Day: {now.day}") # Output: Day: 2
print(f"Hour: {now.hour}") # Output: Hour: 14
print(f"Minute: {now.minute}") # Output: Minute: 30
print(f"Second: {now.second}") # Output: Second: 45Чтобы получить только дату (без времени), используйте класс date:
from datetime import date
# Получить сегодняшнюю дату
today = date.today()
print(f"Today: {today}") # Output: Today: 2026-01-02
print(f"Year: {today.year}") # Output: Year: 2026
print(f"Month: {today.month}") # Output: Month: 1
print(f"Day: {today.day}") # Output: Day: 239.2.2) Создание конкретных дат и времени
Вы можете создавать объекты datetime и date для конкретных моментов времени:
from datetime import datetime, date
# Создать конкретную дату
birthday = date(1995, 7, 15)
print(f"Birthday: {birthday}") # Output: Birthday: 1995-07-15
# Создать конкретный datetime
meeting = datetime(2026, 3, 15, 14, 30) # March 15, 2026 at 2:30 PM
print(f"Meeting: {meeting}") # Output: Meeting: 2026-03-15 14:30:00Это полезно для представления дедлайнов, встреч, исторических дат или любой фиксированной точки во времени:
from datetime import date
# Важные даты в проекте
project_start = date(2026, 1, 15)
project_end = date(2026, 6, 30)
print(f"Project duration: {project_start} to {project_end}")
# Output: Project duration: 2026-01-15 to 2026-06-3039.2.3) Вычисление разницы во времени с timedelta
Класс timedelta представляет длительность — разницу между двумя датами или моментами времени. Его можно использовать, чтобы вычислить, сколько времени прошло, или чтобы добавлять/вычитать время к датам:
from datetime import date, timedelta
# Рассчитать возраст
birth_date = date(1995, 7, 15)
today = date(2026, 1, 2)
age_delta = today - birth_date
print(f"Days since birth: {age_delta.days}") # Output: Days since birth: 11128
print(f"Years (approximate): {age_delta.days // 365}") # Output: Years (approximate): 30Когда вы вычитаете одну дату из другой, вы получаете объект timedelta. Атрибут days сообщает количество дней в этой длительности.
Также можно создавать объекты timedelta напрямую, чтобы представлять конкретные длительности:
from datetime import date, timedelta
# Добавить дни к дате
today = date(2026, 1, 2)
one_week = timedelta(days=7)
next_week = today + one_week
print(f"Today: {today}") # Output: Today: 2026-01-02
print(f"Next week: {next_week}") # Output: Next week: 2026-01-09
# Вычесть дни из даты
thirty_days_ago = today - timedelta(days=30)
print(f"30 days ago: {thirty_days_ago}") # Output: 30 days ago: 2025-12-03timedelta может представлять дни, секунды, микросекунды, миллисекунды, минуты, часы и недели:
from datetime import datetime, timedelta
# Рассчитать дедлайн
now = datetime(2026, 1, 2, 14, 30)
deadline = now + timedelta(hours=48, minutes=30)
print(f"Current time: {now}") # Output: Current time: 2026-01-02 14:30:00
print(f"Deadline: {deadline}") # Output: Deadline: 2026-01-04 15:00:00
# Рассчитать оставшееся время
time_left = deadline - now
print(f"Hours remaining: {time_left.total_seconds() / 3600}") # Output: Hours remaining: 48.5Метод total_seconds() преобразует всю длительность в секунды, которые затем можно перевести в часы, минуты или любую другую единицу.
Вот практический пример вычисления вех проекта:
from datetime import date, timedelta
# Планирование проекта
project_start = date(2026, 1, 15)
sprint_duration = timedelta(weeks=2)
sprint_1_end = project_start + sprint_duration
sprint_2_end = sprint_1_end + sprint_duration
sprint_3_end = sprint_2_end + sprint_duration
print(f"Sprint 1: {project_start} to {sprint_1_end}")
# Output: Sprint 1: 2026-01-15 to 2026-01-29
print(f"Sprint 2: {sprint_1_end} to {sprint_2_end}")
# Output: Sprint 2: 2026-01-29 to 2026-02-12
print(f"Sprint 3: {sprint_2_end} to {sprint_3_end}")
# Output: Sprint 3: 2026-02-12 to 2026-02-2639.2.4) Сравнение дат и времени
Объекты date и datetime можно сравнивать с помощью стандартных операторов сравнения:
from datetime import date
# Сравнить даты
date1 = date(2026, 1, 15)
date2 = date(2026, 2, 20)
date3 = date(2026, 1, 15)
print(date1 < date2) # Output: True
print(date1 == date3) # Output: True
print(date2 > date1) # Output: TrueЭто полезно для проверки дедлайнов, валидации диапазонов дат и сортировки дат:
from datetime import date
# Проверить, находится ли дата в прошлом
event_date = date(2025, 12, 25)
today = date(2026, 1, 2)
if event_date < today:
print("This event has already passed") # Output: This event has already passed
else:
print("This event is upcoming")
# Отсортировать список дат
important_dates = [
date(2026, 3, 15),
date(2026, 1, 10),
date(2026, 2, 28)
]
important_dates.sort()
print("Dates in order:") # Output: Dates in order:
for d in important_dates:
print(f" {d}")
# Output:
# 2026-01-10
# 2026-02-28
# 2026-03-1539.2.5) Форматирование дат и времени с strftime()
Метод strftime() (string format time) преобразует даты и время в форматированные строки. Формат задаётся специальными кодами:
from datetime import datetime
now = datetime(2026, 1, 2, 14, 30, 45)
# Распространённые форматы дат
print(now.strftime("%Y-%m-%d")) # Output: 2026-01-02
print(now.strftime("%m/%d/%Y")) # Output: 01/02/2026
print(now.strftime("%B %d, %Y")) # Output: January 02, 2026
print(now.strftime("%A, %B %d, %Y")) # Output: Friday, January 02, 2026
# Распространённые форматы времени
print(now.strftime("%H:%M:%S")) # Output: 14:30:45
print(now.strftime("%I:%M %p")) # Output: 02:30 PM
# Комбинированные форматы
print(now.strftime("%Y-%m-%d %H:%M:%S")) # Output: 2026-01-02 14:30:45
print(now.strftime("%B %d, %Y at %I:%M %p")) # Output: January 02, 2026 at 02:30 PMРаспространённые коды формата:
| Code | Description | Example |
|---|---|---|
%Y | Год с веком | 2026 |
%m | Месяц как число с ведущим нулём (01-12) | 01 |
%d | День как число с ведущим нулём (01-31) | 02 |
%B | Полное название месяца | January |
%b | Короткое название месяца | Jan |
%A | Полное название дня недели | Friday |
%a | Короткое название дня недели | Fri |
%H | Часы в 24-часовом формате (00-23) | 14 |
%I | Часы в 12-часовом формате (01-12) | 02 |
%M | Минуты (00-59) | 30 |
%S | Секунды (00-59) | 45 |
%p | AM/PM | PM |
Вот практический пример создания записи лога:
from datetime import datetime
def log_event(message):
"""Записать событие с временной меткой"""
now = datetime.now()
timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
log_event("User logged in")
# Output: [2026-01-02 14:30:45] User logged in
log_event("File uploaded successfully")
# Output: [2026-01-02 14:30:45] File uploaded successfully39.2.6) Разбор дат из строк с strptime()
Функция strptime() (string parse time) преобразует форматированные строки обратно в объекты datetime. Вы указываете те же коды формата, чтобы сообщить Python, как интерпретировать строку:
from datetime import datetime
# Разобрать разные форматы дат
date_str1 = "2026-01-15"
date1 = datetime.strptime(date_str1, "%Y-%m-%d")
print(f"Parsed: {date1}") # Output: Parsed: 2026-01-15 00:00:00
date_str2 = "January 15, 2026"
date2 = datetime.strptime(date_str2, "%B %d, %Y")
print(f"Parsed: {date2}") # Output: Parsed: 2026-01-15 00:00:00
# Разобрать datetime со временем
datetime_str = "2026-01-15 14:30:00"
dt = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
print(f"Parsed: {dt}") # Output: Parsed: 2026-01-15 14:30:00Это необходимо при чтении дат из файлов, пользовательского ввода или внешних источников данных:
from datetime import datetime
# Разобрать пользовательский ввод
user_input = "03/15/2026"
try:
event_date = datetime.strptime(user_input, "%m/%d/%Y")
print(f"Event scheduled for: {event_date.strftime('%B %d, %Y')}")
# Output: Event scheduled for: March 15, 2026
except ValueError:
print("Invalid date format. Please use MM/DD/YYYY")Важно: строка формата должна точно соответствовать входной строке, иначе вы получите ValueError:
from datetime import datetime
# Это завершится ошибкой — формат не совпадает
try:
datetime.strptime("2026-01-15", "%m/%d/%Y") # Wrong format
except ValueError as e:
print(f"Error: {e}")
# Output: Error: time data '2026-01-15' does not match format '%m/%d/%Y'39.3) Чтение и запись данных JSON
JSON (JavaScript Object Notation) — это текстовый формат для хранения и обмена структурированными данными. Это самый распространённый формат для веб-API, конфигурационных файлов и обмена данными между программами. Модуль json в Python упрощает преобразование между структурами данных Python и текстом JSON.
39.3.1) Понимание структуры JSON
JSON похож на словари(dict) и списки(list) Python, но есть некоторые отличия:
JSON поддерживает следующие типы данных:
- Objects (как словари Python):
{"name": "Alice", "age": 30} - Arrays (как списки Python):
[1, 2, 3, 4] - Strings:
"hello"(должны использоваться двойные кавычки) - Numbers:
42,3.14 - Booleans:
true,false(в нижнем регистре) - Null:
null(какNoneв Python)
Ключевые отличия от Python:
- JSON использует
true/false/nullвместоTrue/False/Noneв Python - Строки в JSON должны использовать двойные кавычки (
"text"), а не одинарные - JSON не поддерживает кортежи(tuple), множества(set) или пользовательские объекты напрямую
Вот как выглядит JSON-данные:
{
"name": "Alice Johnson",
"age": 30,
"email": "alice@example.com",
"is_active": true,
"scores": [85, 92, 78, 95],
"address": {
"street": "123 Main St",
"city": "Springfield",
"zip": "12345"
}
}Примечание: Это чистый текст JSON, а не код Python. Обратите внимание на true в нижнем регистре и использование двойных кавычек.
39.3.2) Преобразование данных Python в JSON с dumps()
Функция dumps() (dump string) преобразует структуры данных Python в строки в формате JSON:
import json
student = {
"name": "Alice Johnson",
"age": 30,
"email": "alice@example.com",
"is_active": True,
"scores": [85, 92, 78, 95]
}
# Преобразовать словарь в JSON
json_string = json.dumps(student)
print(json_string)
# Output: {"name": "Alice Johnson", "age": 30, "email": "alice@example.com", "is_active": true, "scores": [85, 92, 78, 95]}
print(type(json_string)) # Output: <class 'str'>Обратите внимание, как True в Python превратился в true в JSON в выводе. Функция dumps() автоматически обрабатывает такие преобразования.
Для более читаемого вывода используйте параметр indent:
import json
student = {
"name": "Alice Johnson",
"age": 30,
"scores": [85, 92, 78, 95]
}
# Красивый вывод с отступами
json_string = json.dumps(student, indent=2)
print(json_string)
# Output:
# {
# "name": "Alice Johnson",
# "age": 30,
# "scores": [
# 85,
# 92,
# 78,
# 95
# ]
# }Параметр indent задаёт, сколько пробелов использовать для каждого уровня отступа. Это делает JSON гораздо более читаемым, особенно для сложных вложенных структур.
39.3.3) Преобразование JSON в данные Python с loads()
Функция loads() (load string) преобразует строки в формате JSON обратно в структуры данных Python:
import json
# JSON-строка (как если бы вы получили её от web API)
json_string = '{"name": "Bob Smith", "age": 25, "scores": [90, 88, 92]}'
# Преобразовать в словарь Python
student = json.loads(json_string)
print(student) # Output: {'name': 'Bob Smith', 'age': 25, 'scores': [90, 88, 92]}
print(type(student)) # Output: <class 'dict'>
# Доступ к данным как к любому словарю Python
print(f"Name: {student['name']}") # Output: Name: Bob Smith
print(f"Average score: {sum(student['scores']) / len(student['scores'])}")
# Output: Average score: 90.0true, false и null из JSON автоматически преобразуются в True, False и None в Python:
import json
json_string = '{"active": true, "verified": false, "middle_name": null}'
data = json.loads(json_string)
print(data) # Output: {'active': True, 'verified': False, 'middle_name': None}
print(type(data["active"])) # Output: <class 'bool'>
print(type(data["middle_name"])) # Output: <class 'NoneType'>39.3.4) Запись JSON в файлы с dump()
Функция dump() записывает данные Python напрямую в файл в формате JSON:
import json
# Записи о студентах
students = [
{"name": "Alice", "age": 20, "gpa": 3.8},
{"name": "Bob", "age": 22, "gpa": 3.5},
{"name": "Charlie", "age": 21, "gpa": 3.9}
]
# Записать в JSON-файл
with open("students.json", "w") as file:
json.dump(students, file, indent=2)
print("Data written to students.json")
# Output: Data written to students.jsonПосле выполнения этого кода файл students.json содержит:
[
{
"name": "Alice",
"age": 20,
"gpa": 3.8
},
{
"name": "Bob",
"age": 22,
"gpa": 3.5
},
{
"name": "Charlie",
"age": 21,
"gpa": 3.9
}
]Почему использовать dump(), а не dumps()? Функция dump() пишет напрямую в файл, что эффективнее, чем сначала преобразовать данные в строку, а затем записать строку. Используйте dump() для файлов и dumps(), когда вам нужен JSON в виде строки (например, чтобы отправить по сети).
39.3.5) Чтение JSON из файлов с load()
Функция load() читает данные JSON из файла и преобразует их в структуры данных Python:
import json
# Прочитать JSON-файл, который мы создали ранее
with open("students.json", "r") as file:
students = json.load(file)
print(f"Loaded {len(students)} students") # Output: Loaded 3 students
# Работать с данными
for student in students:
print(f"{student['name']}: GPA {student['gpa']}")
# Output:
# Alice: GPA 3.8
# Bob: GPA 3.5
# Charlie: GPA 3.939.3.6) Обработка ошибок JSON
При работе с JSON вы можете столкнуться с некорректными данными. Всегда обрабатывайте возможные ошибки:
import json
# Некорректный JSON — отсутствует закрывающая кавычка
invalid_json = '{"name": "Alice", "age": 30'
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as e:
print(f"Invalid JSON: {e}")
# Output: Invalid JSON: Expecting ',' delimiter: line 1 column 28 (char 27)Это особенно важно при чтении JSON из внешних источников (файлы, web API, пользовательский ввод), где вы не можете гарантировать валидность данных:
import json
def load_config(filename):
"""Загрузить конфигурацию из JSON-файла с обработкой ошибок"""
try:
with open(filename, "r") as file:
config = json.load(file)
return config
except FileNotFoundError:
print(f"Config file '{filename}' not found")
return None
except json.JSONDecodeError as e:
print(f"Invalid JSON in '{filename}': {e}")
return None
# Попробовать загрузить конфигурацию
config = load_config("config.json")
if config:
print(f"Configuration loaded: {config}")
else:
print("Using default configuration")39.3.7) Практический пример JSON: сохранение и загрузка состояния приложения
Вот полный пример, показывающий, как сохранять и загружать данные приложения:
import json
def save_game_state(filename, player_data):
"""Сохранить состояние игры в JSON-файл"""
with open(filename, "w") as file:
json.dump(player_data, file, indent=2)
print(f"Game saved to {filename}")
def load_game_state(filename):
"""Загрузить состояние игры из JSON-файла"""
try:
with open(filename, "r") as file:
player_data = json.load(file)
print(f"Game loaded from {filename}")
return player_data
except FileNotFoundError:
print("No saved game found")
return None
# Данные игры
player = {
"name": "Hero",
"level": 5,
"health": 85,
"inventory": ["sword", "shield", "potion"],
"position": {"x": 10, "y": 20}
}
# Сохранить игру
save_game_state("savegame.json", player)
# Output: Game saved to savegame.json
# Позже загрузить игру
loaded_player = load_game_state("savegame.json")
# Output: Game loaded from savegame.json
if loaded_player:
print(f"Welcome back, {loaded_player['name']}!")
print(f"Level: {loaded_player['level']}, Health: {loaded_player['health']}")
# Output:
# Welcome back, Hero!
# Level: 5, Health: 8539.4) Практичные контейнеры в collections
Модуль collections предоставляет специализированные типы контейнеров, которые расширяют встроенные контейнеры Python (списки(list), словари(dict), множества(set)) дополнительной функциональностью. Эти контейнеры более элегантно решают распространённые задачи, чем использование базовых структур данных.
39.4.1) Подсчёт элементов с Counter
Класс Counter предназначен для подсчёта хешируемых объектов. Это подкласс словаря, который хранит элементы как ключи и их количества как значения.
Что Counter принимает на вход:
- Любой итерируемый объект(iterable) (список, строка, кортеж и т. д.)
- Другой словарь с количествами
- Именованные аргументы с количествами
Что Counter хранит:
- Словарь, где ключи — это элементы, а значения — их количества
- Пример:
Counter(['a', 'b', 'a'])хранит{'a': 2, 'b': 1}
Ключевое преимущество перед обычными словарями:
- Возвращает 0 для отсутствующих ключей вместо выбрасывания
KeyError - Предоставляет методы, ориентированные на подсчёт, например
most_common() - Поддерживает арифметические операции между счётчиками
Базовое использование
from collections import Counter
# Подсчитать буквы в слове
word = "mississippi"
letter_counts = Counter(word)
print(letter_counts)
# Output: Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
# Доступ к количествам как у словаря
print(f"Number of 'i's: {letter_counts['i']}")
# Output: Number of 'i's: 4
print(f"Number of 'z's: {letter_counts['z']}")
# Output: Number of 'z's: 0 (returns 0 for missing keys, no KeyError!)Создание Counter из разных источников
from collections import Counter
# Из списка
votes = ["Alice", "Bob", "Alice", "Charlie", "Alice", "Bob", "Alice"]
vote_counts = Counter(votes)
print(vote_counts)
# Output: Counter({'Alice': 4, 'Bob': 2, 'Charlie': 1})
# Из строки (считает каждый символ)
letter_counts = Counter("hello")
print(letter_counts)
# Output: Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
# Из словаря
existing_counts = {'apple': 3, 'banana': 2}
fruit_counts = Counter(existing_counts)
print(fruit_counts)
# Output: Counter({'apple': 3, 'banana': 2})
# Из именованных аргументов
color_counts = Counter(red=5, blue=3, green=2)
print(color_counts)
# Output: Counter({'red': 5, 'blue': 3, 'green': 2})Поиск самых частых элементов с most_common()
Сигнатура метода: most_common(n=None)
Параметры:
n(необязательно): количество самых частых элементов, которые нужно вернуть- Если
nопущен или равенNone, возвращает все элементы
Возвращает:
- Список кортежей(tuple)
(item, count) - Отсортированный по количеству, по убыванию
- Если количества равны, элементы идут в порядке первого появления
from collections import Counter
# Анализ частоты слов в тексте
text = "the quick brown fox jumps over the lazy dog the fox"
words = text.split()
word_counts = Counter(words)
# Получить 3 самых частых слова
top_3 = word_counts.most_common(3)
print(top_3)
# Output: [('the', 3), ('fox', 2), ('quick', 1)]Арифметические операции над Counter
Вы можете складывать, вычитать и выполнять другие операции с объектами Counter:
from collections import Counter
# Подсчитать элементы в двух группах
group1 = Counter(["apple", "banana", "apple", "orange"])
print(group1)
# Output: Counter({'apple': 2, 'banana': 1, 'orange': 1})
group2 = Counter(["banana", "banana", "grape", "apple"])
print(group2)
# Output: Counter({'banana': 2, 'grape': 1, 'apple': 1})
# Сложить количества
combined = group1 + group2
print(combined)
# Output: Counter({'apple': 3, 'banana': 3, 'orange': 1, 'grape': 1})
# Вычесть количества (оставляет только положительные результаты)
difference = group1 - group2
print(difference)
# Output: Counter({'apple': 1, 'orange': 1})
# banana: 1 - 2 = -1 (negative, so excluded)
# grape: not in group1, so excludedПрактический пример: анализ оценок студентов
from collections import Counter
# Распределение оценок
grades = ["A", "B", "A", "C", "B", "A", "B", "D", "A", "B", "C", "A"]
grade_counts = Counter(grades)
print(f"Total students: {len(grades)}")
# Output: Total students: 12
print("\nGrade Distribution:")
for grade, count in grade_counts.most_common():
percentage = (count / len(grades)) * 100
bar = "█" * count
print(f" {grade}: {count} students ({percentage:4.1f}%) {bar}")
# Output:
# Grade Distribution:
# A: 5 students (41.7%) █████
# B: 4 students (33.3%) ████
# C: 2 students (16.7%) ██
# D: 1 students ( 8.3%) █39.4.2) Словари со значениями по умолчанию с defaultdict
Класс defaultdict — это подкласс словаря(dict), который автоматически создаёт записи со значением по умолчанию, когда вы обращаетесь к отсутствующему ключу. Это устраняет необходимость проверять существование ключей перед использованием.
Что defaultdict принимает на вход:
- Функцию default factory (обязательно): вызываемый объект, который возвращает значение по умолчанию для отсутствующих ключей
- Любые аргументы, которые принимает обычный
dict(пары ключ-значение, другой словарь, именованные аргументы)
Ключевое преимущество перед обычными словарями:
- Не нужно проверять, существует ли ключ перед использованием
- Автоматически инициализирует отсутствующие ключи значением по умолчанию
- Более чистый и читаемый код для операций группировки, подсчёта и накопления
Понимание default factory
Когда вы создаёте defaultdict, вы должны указать default factory — вызываемый объект (функцию), который не принимает аргументов и возвращает значение по умолчанию. Распространённые default factory:
int— возвращает0(полезно для подсчёта)list— возвращает[](полезно для группировки элементов)set— возвращаетset()(полезно для сбора уникальных элементов)str— возвращает''(полезно для конкатенации строк)lambda: value— возвращает произвольное значение по умолчанию
from collections import defaultdict
# Разные default factory
counts = defaultdict(int) # Для отсутствующих ключей возвращается 0
groups = defaultdict(list) # Для отсутствующих ключей возвращается []
unique = defaultdict(set) # Для отсутствующих ключей возвращается set()
custom = defaultdict(lambda: "N/A") # Для отсутствующих ключей возвращается "N/A"
# Проверка на отсутствующих ключах
print(counts['missing']) # Output: 0
print(groups['missing']) # Output: []
print(unique['missing']) # Output: set()
print(custom['missing']) # Output: N/AБазовое использование: подсчёт с defaultdict
Сравнение обычного словаря и defaultdict для подсчёта:
from collections import defaultdict
word = "mississippi"
# Обычный словарь — нужно проверять, существует ли ключ
regular_dict = {}
for letter in word:
if letter not in regular_dict:
regular_dict[letter] = 0
regular_dict[letter] += 1
print(regular_dict)
# Output: {'m': 1, 'i': 4, 's': 4, 'p': 2}
# defaultdict — автоматически создаёт записи со значением по умолчанию
letter_counts = defaultdict(int) # int() возвращает 0
for letter in word:
letter_counts[letter] += 1 # Не нужно проверять, существует ли ключ!
print(dict(letter_counts))
# Output: {'m': 1, 'i': 4, 's': 4, 'p': 2}Как это работает:
- Когда вы обращаетесь к
letter_counts[letter]для новой буквы,defaultdictвызываетint(), который возвращает0 - Ключ создаётся со значением
0, затем+= 1делает его равным1 - Для существующих ключей он ведёт себя как обычный словарь
Группировка элементов с defaultdict(list)
Распространённый сценарий — группировать элементы по категориям:
from collections import defaultdict
students = [
("Alice", "A"),
("Bob", "B"),
("Charlie", "A"),
("Diana", "C"),
("Eve", "B"),
("Frank", "A")
]
# Сгруппировать студентов по оценке
# С defaultdict — чисто и просто
students_by_grade = defaultdict(list)
for name, grade in students:
students_by_grade[grade].append(name)
print(dict(students_by_grade))
# Output: {'A': ['Alice', 'Charlie', 'Frank'], 'B': ['Bob', 'Eve'], 'C': ['Diana']}
# Обратиться к оценке, которой ещё нет
print(students_by_grade["D"]) # Output: [] (empty list, not KeyError!)Как это работает:
- Когда вы обращаетесь к
students_by_grade[grade]для новой оценки,defaultdictвызываетlist(), который возвращает[] - Ключ создаётся с пустым списком, затем
.append(name)добавляет первого студента - Для существующих оценок он просто добавляет в уже существующий список
Создание defaultdict из существующего словаря
Можно инициализировать defaultdict существующими данными:
from collections import defaultdict
# Начать с уже существующих подсчётов
existing_data = {'apple': 5, 'banana': 3}
# Создать defaultdict из существующего словаря
fruit_counts = defaultdict(int, existing_data)
# Добавить ещё подсчётов
fruit_counts['apple'] += 2 # 5 + 2 = 7
fruit_counts['orange'] += 1 # 0 + 1 = 1 (new key, starts at 0)
print(dict(fruit_counts))
# Output: {'apple': 7, 'banana': 3, 'orange': 1}Пользовательская default factory
В качестве default factory можно передать любой вызываемый объект:
from collections import defaultdict
# Использовать lambda для пользовательских значений по умолчанию
page_views = defaultdict(lambda: {'views': 0, 'unique': 0})
page_views['home']['views'] = 100
page_views['home']['unique'] = 75
print(page_views['home'])
# Output: {'views': 100, 'unique': 75}
print(page_views['about']) # New key gets default dictionary
# Output: {'views': 0, 'unique': 0}Важные замечания
Доступ vs. проверка наличия ключей:
from collections import defaultdict
counts = defaultdict(int)
# Доступ к отсутствующему ключу СОЗДАЁТ его
value = counts['missing'] # Creates 'missing' with value 0
print('missing' in counts) # Output: True
# Чтобы проверить без создания, используйте 'in' или .get()
counts2 = defaultdict(int)
print('missing' in counts2) # Output: False (doesn't create key)
print(counts2.get('missing')) # Output: None (doesn't create key)39.5) (Необязательно) Полезные инструменты итерации
Модуль itertools предоставляет функции для создания эффективных итераторов(iterator). Эти инструменты помогают мощно работать с последовательностями, не создавая большие промежуточные списки.
39.5.1) Объединение итерируемых объектов с chain()
Функция chain() объединяет несколько итерируемых объектов в один итератор, который выдаёт элементы из каждого итерируемого объекта последовательно.
Что принимает chain():
- Несколько итерируемых объектов (списки, кортежи, строки и т. д.) как отдельные аргументы
Что возвращает chain():
- Итератор, который выдаёт все элементы из первого итерируемого объекта, затем все элементы из второго и т. д.
Ключевое преимущество:
- Более экономно по памяти, чем конкатенация с
+(не создаёт промежуточные списки) - Работает с любым итерируемым объектом, не только со списками
from itertools import chain
# Объединить несколько списков
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]
combined = chain(list1, list2, list3)
print(list(combined)) # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]Это более экономно по памяти, чем объединение списков с +, особенно для больших последовательностей:
from itertools import chain
# Обработать несколько источников данных, не создавая большой объединённый список
students_class_a = ["Alice", "Bob", "Charlie"]
students_class_b = ["Diana", "Eve", "Frank"]
students_class_c = ["Grace", "Henry", "Iris"]
# Пройти по всем студентам, не создавая объединённый список
for student in chain(students_class_a, students_class_b, students_class_c):
print(f"Processing: {student}")
# Output:
# Processing: Alice
# Processing: Bob
# Processing: Charlie
# Processing: Diana
# Processing: Eve
# Processing: Frank
# Processing: Grace
# Processing: Henry
# Processing: IrisМожно объединять разные типы итерируемых объектов:
from itertools import chain
# Объединить списки, кортежи и строки
numbers = [1, 2, 3]
letters = ("a", "b", "c")
word = "xyz"
combined = chain(numbers, letters, word)
print(list(combined)) # Output: [1, 2, 3, 'a', 'b', 'c', 'x', 'y', 'z']39.5.2) Повторение элементов с cycle()
Функция cycle() создаёт бесконечный итератор, который повторно циклически проходит по элементам итерируемого объекта.
Что принимает cycle():
- Один итерируемый объект (список, кортеж, строка и т. д.)
Что возвращает cycle():
- Бесконечный итератор, который выдаёт элементы итерируемого объекта снова и снова
- Достигнув конца, он начинает сначала
Ключевые характеристики:
- Создаёт бесконечный итератор — сам по себе никогда не остановится
- Должен использоваться с условием остановки (счётчик,
breakилиzip()) - Экономен по памяти: не создаёт копии данных
from itertools import cycle
# Создать бесконечный цикл цветов
colors = cycle(["red", "green", "blue"])
# Взять первые 10 цветов
for i, color in enumerate(colors):
if i >= 10:
break
print(f"Item {i}: {color}")
# Output:
# Item 0: red
# Item 1: green
# Item 2: blue
# Item 3: red
# Item 4: green
# Item 5: blue
# Item 6: red
# Item 7: green
# Item 8: blue
# Item 9: redПредупреждение: cycle() создаёт бесконечный итератор. Всегда используйте его с условием остановки (например, счётчиком или оператором break), иначе вы получите бесконечный цикл(loop).
Практический пример — чередование значений:
from itertools import cycle
# Чередовать два фоновых цвета для строк таблицы
row_colors = cycle(["white", "lightgray"])
rows = ["Row 1", "Row 2", "Row 3", "Row 4", "Row 5"]
for row, color in zip(rows, row_colors):
print(f"{row}: background-color: {color}")
# Output:
# Row 1: background-color: white
# Row 2: background-color: lightgray
# Row 3: background-color: white
# Row 4: background-color: lightgray
# Row 5: background-color: whiteЗдесь мы используем zip() (который мы изучили в главе 37), чтобы сопоставить каждой строке цвет. Итератор cycle() автоматически повторяет цвета по мере необходимости.
39.5.3) Комбинирование chain() и cycle()
Вы можете комбинировать функции itertools для более сложных шаблонов:
from itertools import chain, cycle
# Создать шаблон, который циклично проходит по нескольким последовательностям
pattern1 = [1, 2, 3]
pattern2 = [10, 20]
# Объединить шаблоны, затем зациклить результат
combined_pattern = cycle(chain(pattern1, pattern2))
# Взять первые 12 значений
for i, value in enumerate(combined_pattern):
if i >= 12:
break
print(value, end=" ")
# Output: 1 2 3 10 20 1 2 3 10 20 1 2
print() # NewlineЭто создаёт повторяющийся шаблон: 1, 2, 3, 10, 20, 1, 2, 3, 10, 20, ...
Вот практический пример создания ротационного расписания:
from itertools import cycle
# Создать ротационное расписание для членов команды
team_members = ["Alice", "Bob", "Charlie"]
schedule = cycle(team_members)
# Назначать задачи членам команды по кругу
tasks = [
"Review code",
"Write tests",
"Update documentation",
"Fix bug #123",
"Implement feature X",
"Deploy to staging"
]
print("Task Assignments:")
for task, assignee in zip(tasks, schedule):
print(f" {assignee}: {task}")
# Output:
# Task Assignments:
# Alice: Review code
# Bob: Write tests
# Charlie: Update documentation
# Alice: Fix bug #123
# Bob: Implement feature X
# Charlie: Deploy to stagingВ этой главе мы рассмотрели пять ключевых модулей стандартной библиотеки, которые расширяют возможности Python:
random: генерирует случайные числа, выполняет случайный выбор и перемешивает последовательности — важно для симуляций, игр и тестированияdatetime: работает с датами, временем и длительностями — рассчитывает возраст, планирует события и форматирует временные меткиjson: обеспечивает обмен данными с другими программами с помощью универсального формата JSON — сохраняет состояние приложения, работает с web API и хранит конфигурациюcollections: предоставляет специализированные контейнеры, такие какCounterдля подсчёта иdefaultdictдля автосоздания ключейitertools: создаёт эффективные итераторы сchain()для объединения последовательностей иcycle()для повторяющихся шаблонов
Эти модули — часть стандартной библиотеки Python: они всегда доступны, хорошо протестированы и элегантно решают распространённые задачи программирования. По мере того как вы будете создавать более сложные программы, вы будете часто обращаться к этим инструментам. Они отражают философию Python «batteries included» — предоставление мощных, готовых к использованию решений для повседневных задач программирования.