18  Стандартная библиотека Python.

На этом занятии мы с вами обсудим основные библиотеки из стандартного набора в Python, их назначение и применение. Здесь будет представлен далеко не весь перечень, а те библиотеки, которые вам могут понадобится для решения текущих жизненных задач с поправкой на имеющийся у вас на данный момент времени опыт. Структура этой главы будет напоминать FAQ (Frequently Asked Questions, часто задаваемые вопросы).

18.1 Как сгенерировать идентификатор и быть полностью уверенным в его уникальности?

Часто в качестве идентификаторов используют либо порядковые числа, либо некоторую позиционно закодированную строку (каждая позиция несет определенный смысл). Такой подход хорош в условиях небольшого количества данных, которые хранятся централизовано и к которые часто используют люди. Если же нам необходимо или хранение больших массивов данных, или к которым не будет иметь прямого доступа человек, или данные которые будут хранится распределенно, то обесспечить уникальность идентификаторов подобным образом будет сложно. Для этого нужна библиотека uuid (универсальный уникальный идентификатор). Примеры использования показаны на Listing 18.1. Результат - уникальное 128-битное значение.

Listing 18.1: Пример использования uuid
import uuid 

1print(uuid.uuid1())
2print(uuid.uuid4())
1
Генерирует универсальный идентификатор на основе имени компьютера и текущего времени
2
Генерирует случайный идентификатор
662868cc-ce85-11f0-9e8f-586c259e21c2
ccafcd42-0589-4579-b960-ccbd6bb82156

18.2 Как работать с датой и временем?

Дата и время представляют собой особый тип данных со своим особым спектром операций. На машинном уровне работа с датами осуществляется довольно просто. Согласно стандарту POSIX текущее дата и время определяется как число секунд, прошедших с полуночи 1 января 1970 года по Гринвичу (UTC+0). Операции над датой и временем работают как обычные арифметические операции. Для человека такой формат неудобен, т.к. необходимо оперировать днями, месяцами, учитывать разницу в часовых поясах и календарных системах, високосные кода. В этом нам поможет библиотека datetime. Смотри на Listing 18.2.

Listing 18.2: Операции над датами
from datetime import datetime, timedelta

skynet_critical = "29.08.1997 02:14:53"
1skynet_critical_date = datetime.strptime(skynet_critical, "%d.%m.%Y %H:%M:%S")
2today = datetime.now()
3time_left = today - skynet_critical_date
4print(today.strftime("%Y-%m-%d %H:%M:%S"))
5print(time_left)
6print(today.year)

7meeting_time = datetime(2025, 6, 19, 15, 0, 0)
8reminder_time = meeting_time - timedelta(minutes=30)
print(reminder_time.strftime("%Y-%m-%d %H:%M:%S"))
1
Объект даты можно создать из строки, для этого нужно указать формат, в котором записана ваша дата.
2
Получить текущую дату и время
3
Рассчитать разницу между двумя датами
4
Преобразовать дату в строку. Для этого также нужен строка формата
5
Вывести результат разницы. Лучше используйте strftime
6
Получить компоненту даты (год, число, месяц).
7
Создание объекта даты напрямую из конструктура
8
Прибавление/вычитание к нужной дате определенного временного промежутка.
2025-12-01 10:14:38
10321 days, 7:59:45.844084
2025
2025-06-19 14:30:00

Для работы с календарем существует модуль calendar. Примеры в Listing 18.3.

Listing 18.3: Операции с календарём
from datetime import datetime
import calendar

1print(calendar.month(2025, 12))
2print(calendar.isleap(2025))
today = datetime.now()
3print(calendar.weekday(today.year, today.month, today.day))
1
Получить кадендарь на месяц
2
Проверить год на високосность
3
Получить день недели
   December 2025
Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

False
0

18.3 Как отслеживать выполнение программы?

При написании и дальнейшем использовании сложных программ возникает потребность отслеживания их выполнения для обнаружения внештатных ситуаций и причин их возникновения. Для этого в языках программирования есть возможность журналирования действий. Для этого существует модуль logging, пример использования которого вы увидете в Listing 18.4. logging поддерживает следующие возможности:

  • Настраивает ведение журнала с различными уровнями детализации (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  • Поддерживает несколько выходных устройств, включая терминал и физические файлы.
  • Позволяет легко форматировать сообщения журнала
  • Облегчает ведение журнала в нескольких модулях
  • Обеспечивает иерархию регистраторов для детального контроля
Listing 18.4: Журналирование операций
import logging

1logging.basicConfig(level=logging.INFO,format='%(levelname)s: %(message)s')
logging.info("This is an info message")

2logger = logging.getLogger("custom_logger")
logger.warning("This is a warning from custom_logger")
1
Настройка основных параметров ведения журнала
2
Создание и использование именованного регистратора

18.4 Работа с файлами конфигурации, сохранение состояния объектов

Конфигурационные файлы в современном мире принято сохранять в двух форматах: JSON и YAML. Обработка формата yaml лежит за пределами стандартной библиотеки, а json формат является прямым аналогом питоновского словаря,поэтому в python удобно работать с json форматом, хранить в нем информацию об состояниях и конфигурации программы. Пример работы показан в Listing 18.5. Иногда бывает необходимо кэшировать сложные объекты, которые тяжело или невозможно представить в виде словаря и которые нужно передавать по сети распределенных вычислений. Для работы с такими данными рекомендуется использовать библиотеку pickle из Listing 18.6. Библиотека pickle использует механизм сериализации.

Сериализация

это процесс преобразования структуры данных (например, объекта в памяти) в поток байтов для сохранения или передачи.

Десериализация

Обратный процесс

Listing 18.5: Работа с json форматом
import json
config_file = "user_config.json"

1with open(config_file, mode="r", encoding="utf-8") as file:
    config = json.load(file)

2config["user"]["name"] = "Charlie"
config["user"]["preferences"]["theme"] = "dark"

3with open(config_file, mode="w", encoding="utf-8") as file:
    json.dump(config, file, indent=4)

data = {"name": "Bob", "age": 25} 
4json_str = json.dumps(data)

5data = json.loads('{"name": "Bob", "age": 25}')
1
Загрузка содержимого json в словарь
2
Изменение конфигурации
3
Сохранения словаря в формате json
4
Преобразование словаря в строку в формате json
5
Создания словаря из строки, записанной в формате json
Listing 18.6: Сериализация/десериализация с pickle
import pickle
data = {"key": "value", "number": 42}

1with open("data.pkl", "wb") as file:
    pickle.dump(data, file)

2with open("data.pkl", "rb") as file:
    loaded_data = pickle.load(file)
1
Сериализация объекта
2
Десериализация объекта
Important

Загрузка сериализованных данных из ненадёжных источников может привести к выполнению произвольного кода, что представляет серьёзную угрозу безопасности. Загружать сериализованные данные следует только из надёжных источников!

18.5 Аккуратная платформо-независимая работа с путями и файловой системой

Для минимизации ошибок, связанных с разной записиью путей в различных операционных системах, существует модуль pathlib, который реализует также часть продвинутого функционала, такой как глоббинг - прочесывание файловой системы на наличие файлов, соответствующих некоторому паттерну. Пример продемонстрирован в Listing 18.7. Эта библиотека позволяет в некоторых случаях не использовать функции из модуля os. Для высокоуровневой работы над файловой системой существует модуль shutil. Он позволяет копировать, перемещать, удалять, архивировать файлы и папки, проверять свободное место на диске перед операцией. Пример продемонстрирован на Listing 18.8.

Listing 18.7: Работа с путями через pathlib
from pathlib import Path
1bin = Path("/usr/bin")
2bin.exists()

dir = Path("new_folder")
3dir.mkdir()
dir.exists()  

file = Path("example.txt")
4file.write_text("Hello, World!")
5file.read_text()

6for file in Path(".").iterdir():
   print(file)

project_dir = Path("project")
7python_files = list(project_dir.rglob("*.py"))
python_files
1
Создание объекта
2
Проверка на существования пути
3
Создание папки
4
Запись текста в файл
5
Чтение текста из файла
6
Проверка содержимого папки
7
Рекурсивный поиск по паттерну в папке
Listing 18.8: Работа с shutil
import shutil

1shutil.rmtree("directory")
2shutil.move("example.txt", "/new/location/example.txt")
3shutil.make_archive("target_archive", "zip", target_dir)
1
Удаление папки со всем её содержимым
2
Перемещение файла в новое расположение
3
Архивирование папки target_dir.

18.6 Запуск программ

Запуск и обработка дочерних процесов (не путать с multiprocessing!) осуществляется с помощью модуля subprocess. Такой функционал крайне необходим в биоинформатике, когда необхходимо запустить написанную другим разработчиком утилиту. Пример показан на Listing 18.9.

Listing 18.9: Запуск дочерних процессов
import subprocess

1result = subprocess.run(["echo", "Hello, World!"], capture_output=True, text=True)
2print(result.stdout)
3result = subprocess.run("ls -l", capture_output=True, text=True, shell = True)

4process = subprocess.Popen(["cat"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
5output, _ = process.communicate("Hello from Popen!")
6print(output)
1
Запуск программы из списка аргументов
2
Получение потока вывода запущенной программы
3
Запуск программы из строки-команды
4
Построение конвейера команд
5
Передача input в процесс
6
Вывод результата - “Hello from Popen!”

18.7 Как создать простой объект?

Часто возникает ситуация, когда бывает нужен простой объект без специфичного поведения: только свойства и методы доступа к ним. Здесь на помощь к нам придут именованные кортежи из collections и dataclass из dataclasses. Именнованные кортежи исторически появились раньше, используют меньше памяти и создают immutable объекты. dataclass более новая особенность языка, которая обладает более аккуратным синтаксисом. Примеры представлены в Listing 18.10.

Listing 18.10: Plain Old Python Object
from dataclasses import dataclass
from collections import namedtuple
1@dataclass
class Circle:
2    radius: float = 1.0


circle = Circle()
print(circle.radius)

3Circle = namedtuple("Circle", ["radius"], defaults=[1.0])
circle = Circle()
print(circle.radius)
1
Определение класса с помощью специального декоратора
2
Задание значения по умолчанию
3
То же самое с помощью именнованного кортежа
1.0
1.0

Модуль collections также содержит имплементации нескольких полезных структур данных: отсортированный словарь, счётчик, двусторонюю очередь и другие. Пример использования счётчика продемонстрирован на Listing 18.11.

Listing 18.11: Подсчёт встречаемости слов
from collections import Counter, OrderedDict

text = "lorem ipsum dolor sit amet ipsum lorem"
word_counts = Counter(text.split())
ordered_word_counts = OrderedDict(word_counts.most_common())
ordered_word_counts
OrderedDict([('lorem', 2),
             ('ipsum', 2),
             ('dolor', 1),
             ('sit', 1),
             ('amet', 1)])

18.8 Работа с регулярными выражениями

Listing 18.12: Работа с регулярными выражениями
import re
1pattern = r"\d+"
2print(re.findall(pattern, "There are 42 apples and 100 oranges"))
3match = re.search(pattern, "There are 42 apples")
4print(match.group(0))
5print(re.sub(pattern, "#", "Room 123, Floor 4"))
6print(re.split(r"\s+", "There are 42 apples and 100 oranges"))
1
Регулярное выражение
2
Поиск всех не перекрывающихся вхождений паттерна в строку
3
Поиск любых вхождений паттерна в строке
4
Вывод найденого вхождения.
5
Замена найденного паттерна на строку
6
Разбиение строки по паттерну.
['42', '100']
42
Room #, Floor #
['There', 'are', '42', 'apples', 'and', '100', 'oranges']

18.9 Работа с комбинаторикой

Эффективная по памяти работа с комбинаторикой за счёт использования генераторов.

Listing 18.13: Подсчёт встречаемости слов
from itertools import cycle, combinations, permutations, chain
1print(list(chain([1, 2], [3, 4], [5, 6])))
2colors = cycle(["red", "green", "blue"])
print([next(colors) for _ in range(6)])
3print(list(combinations("ABC", 2)))
guests = ["Alice", "Bob", "Carol"]
4print(list(permutations(guests)))
1
Работа с вложенными конструкциями
2
Создание повторяющихся конструкций
3
Комбинации из n по k (2 по 3)
4
Все возможные перестановки
[1, 2, 3, 4, 5, 6]
['red', 'green', 'blue', 'red', 'green', 'blue']
[('A', 'B'), ('A', 'C'), ('B', 'C')]
[('Alice', 'Bob', 'Carol'), ('Alice', 'Carol', 'Bob'), ('Bob', 'Alice', 'Carol'), ('Bob', 'Carol', 'Alice'), ('Carol', 'Alice', 'Bob'), ('Carol', 'Bob', 'Alice')]

18.10 Ввод-вывод

Listing 18.14: Подсчёт встречаемости слов
import io
1stream = io.StringIO("Welcome to Real Python!")
print(stream.read())
2binary_stream = io.BytesIO(b"Binary data")
print(binary_stream.read())
1
Преобразование строки в поток байтов
2
Преобразование потока байтов в строку
Welcome to Real Python!
b'Binary data'

18.11 Хэш-функции

Listing 18.15: Расчёт значений хэш-функций
import hashlib

1hash_object = hashlib.md5(b"Real Python")
print(hash_object.hexdigest())

hash_object = hashlib.sha256()
2hash_object.update(b"Real ")
hash_object.update(b"Python")
print(hash_object.hexdigest())
1
Расчет хэш-функции от объекта
2
Частичный расчёт хэш-функции
5245ae598714e551418aa6d5cc2cf5bc
4a2b42c72ead91c16165d81622a347d5d65addb3a6984927b8322af26827baf3

18.12 Работа с обыкновенными дробями

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

Listing 18.16: Операции над обыкновенными дробями
from fractions import Fraction

1ingredient_costs = [Fraction("1/3"), Fraction("2/5"), Fraction("1/2")]
total_cost = sum(ingredient_costs)
print(total_cost)
1
Создание обыкновенной дроби из строки
37/30

18.13 Задание для закрепления

Note
  1. Выполнять в Jupyter Notebook.
  2. Использовать функционал станартной библиотеки!
  1. Возьмите любое стихотворное произведение и подсчитайте в нём количество символов.

  2. Отсортируйте словарь из п.1 и сохраните его в формате json.

  3. Поделите количество символов на количество слов (обыкновенная дробь!) и сохраните в формате pkl

  4. Рассчитайте количество времени, которое прошло со времени написания автором этого стихотворения. Какой это был день недели, был ли этот год високосным.

  5. Из скольких слов состоит наидлиннейшее предложение? Рассчитайте от него хэш-функцию md5.

  6. Прочитайте сохранённый файл pkl, удалите значения с ключами, которые не являются буквами и пересохраните в pkl.

  7. Создайте класс Vector3D с помощью dataclass и именнованный кортеж с такими же полями. Реализуйте функцию для расчёта модуля вектора. Будет ли он одинаково работать с dataclass и namedtuple?

  8. Получите все возможные сочетания значений двух шестигранных игральных кубиков.

  9. Создайте папку и скопируйте туда созданные вами файлы.

  10. Преобразуйте стихотворение в поток байтов и сохраните его в файл.