Основные библиотеки Python, которых вам не хватает
Известно, что Python поставляется с «батарейками в комплекте» благодаря его очень обширной стандартной библиотеке, которая включает в себя множество модулей и функций, которых вы не ожидаете. Тем не менее, есть ещё много полезных библиотек, о которых вы должны знать и которые вы должны использовать во всех своих проектах Python, и вот их список.
Утилиты общего назначения
Мы начнём с пары библиотек общего назначения, которые вы можете использовать во многих проектах. Первая описана в документах как:
«Boltons — это набор утилит на чистом Python в том же духе, что и в стандартной библиотеке, но явно отсутствующий в ней».
Нам понадобилась бы целая статья, чтобы рассмотреть каждую функцию и особенность boltons
, но вот пара примеров удобных функций:
# pip install boltons
from boltons import jsonutils, timeutils, iterutils
from datetime import date
# {"name": "John", "id": 1, "active": true}
# {"name": "Ben", "id": 2, "active": false}
# {"name": "Mary", "id": 3, "active": true}
with open('input.jsonl') as f:
for line in jsonutils.JSONLIterator(f): # Automatically converted to dict
print(f"User: {line['name']} with ID {line['id']} is {'active' if line['active'] else 'inactive'}")
# User: John with ID 1 is active
# ...
start_date = date(year=2023, month=4, day=9)
end_date = date(year=2023, month=4, day=30)
for day in timeutils.daterange(start_date, end_date, step=(0, 0, 2)):
print(repr(day))
# datetime.date(2023, 4, 9)
# datetime.date(2023, 4, 11)
# datetime.date(2023, 4, 13)
data = {"deeply": {"nested": {"python": {"dict": "value"}}}}
iterutils.get_path(data, ("deeply", "nested", "python"))
# {'dict': 'value'}
data = {"id": "234411",
"node1": {"id": 1234, "value": "some data"},
"node2": {"id": "2352345",
"node3": {"id": "123422", "value": "more data"}
}
}
iterutils.remap(data, lambda p, k, v: (k, int(v)) if k == 'id' else (k, v))
Хотя стандартная библиотека Python имеет модуль json
, она не поддерживает формат JSON Lines (.jsonl
). В первом примере показано, как вы можете обрабатывать jsonl
с помощью библиотеки boltons
.
Второй пример демонстрирует модуль boltons.timeutils
, который позволяет создавать диапазоны дат. Вы можете перебрать их и установить аргумент step
, например, получать через день. Опять же, это то, чего не хватает в модуле Python datetime
.
Наконец, в третьем примере мы используем функцию remap
из модуля boltons.iterutils
для рекурсивного преобразования всех полей id
словаря в целые числа. Здесь boltons.iterutils
служит хорошим расширением для встроенного itertools
.
Говоря о iterutils
и itertools
, следующая отличная библиотека, которую вам нужно проверить, это more-itertools
, которая предоставляет гораздо больше itertools
.
Последней в этой категории является библиотека sh
, которая является заменой модуля subprocess
. Будет здорово, если вы обнаружите, что в Python вы управляете множеством других процессов:
# https://pypi.org/project/sh/
# pip install sh
import sh
# Run any command in $PATH...
print(sh.ls('-la'))
# total 36
# drwxrwxr-x 2 martin martin 4096 apr 8 14:18 .
# drwxrwxr-x 41 martin martin 20480 apr 7 15:23 ..
# -rw-rw-r-- 1 martin martin 30 apr 8 14:18 examples.py
with sh.contrib.sudo:
# Do stuff using 'sudo'...
...
# Write to a file:
sh.ifconfig(_out='/tmp/interfaces')
# Piping:
print(sh.wc('-l', _in=sh.ls('.', '-1')))
# Same as 'ls -1 | wc -l'
Когда мы вызываем sh.some_command
, библиотека sh
пытается найти встроенную команду shell
или двоичный файл $PATH
с таким именем. Если она найдёт такую команду, она просто выполнит её для вас.
Если вам нужно использовать sudo
, вы можете использовать контекстный менеджер sudo
из модуля contrib
, как показано во второй части фрагмента.
Чтобы записать вывод команды в файл, вам нужно только указать аргумент _out
. И, наконец, вы также можете использовать каналы ( |
) с помощью аргумента _in
.
Валидация данных
Ещё одна недостающая часть в стандартной библиотеке Python — это категория инструментов проверки данных. Одна небольшая библиотека, обеспечивающая это, называется validators
. Эта библиотека позволяет вам проверять общие шаблоны, такие как электронные письма, IP-адреса или кредитные карты:
# https://python-validators.github.io/validators/
# pip install validators
import validators
validators.email('someone@example.com') # True
validators.card.visa('...')
validators.ip_address.ipv4('1.2.3.456') # ValidationFailure(func=ipv4, args={'value': '1.2.3.456'})
Далее идёт нечёткое сравнение строк — difflib
, но этот модуль нуждается в некоторых улучшениях. Некоторые из них можно найти в библиотеке thefuzz
(ранее известной как fuzzywuzzy
):
# pip install thefuzz
from thefuzz import fuzz
from thefuzz import process
print(fuzz.ratio("Some text for testing", "text for some testing")) # 76
print(fuzz.token_sort_ratio("Some text for testing", "text for some testing")) # 100
print(fuzz.token_sort_ratio("Some text for testing", "some testing text for some text testing")) # 70
print(fuzz.token_set_ratio("Some text for testing", "some testing text for some text testing")) # 100
songs = [
'01 Radiohead - OK Computer - Airbag.mp3',
'02 Radiohead - OK Computer - Paranoid Android.mp3',
'04 Radiohead - OK Computer - Exit Music (For a Film).mp3',
'06 Radiohead - OK Computer - Karma Police.mp3',
'10 Radiohead - OK Computer - No Surprises.mp3',
'11 Radiohead - OK Computer - Lucky.mp3',
'02 Radiohead - Pablo Honey - Creep.mp3',
'04 Radiohead - Pablo Honey - Stop Whispering.mp3',
'06 Radiohead - Pablo Honey - Anyone Can Play Guitar.mp3',
"10 Radiohead - Pablo Honey - I Can't.mp3",
'13 Radiohead - Pablo Honey - Creep (Radio Edit).mp3',
# ...
]
print(process.extract("Radiohead - No Surprises", songs, limit=1, scorer=fuzz.token_sort_ratio))
# [('10 Radiohead - OK Computer - No Surprises.mp3', 70)]
Привлекательность библиотеки thefuzz
заключается в функциях *ratio
, которые, вероятно, будут работать лучше, чем встроенные difflib.get_close_matches
или difflib.SequenceMatcher.ratio
. Фрагмент выше показывает их различное использование. Во-первых, мы используем базовый ratio
, который вычисляет простую оценку сходства двух строк. После этого мы используем token_sort_ratio
which, игнорируя порядок токенов (слов) в строке при вычислении сходства. Наконец, мы тестируем функцию token_set_ratio
, которая вместо этого игнорирует повторяющиеся токены.
Мы также используем функцию extract
из модуля process
, которая является альтернативой difflib.get_close_matches
. Эта функция ищет наилучшее совпадение в списке строк.
Если вы уже используете difflib
и думаете, стоит ли вам использовать thefuzz
вместо этого, то обязательно ознакомьтесь со статьей автора библиотеки, в которой хорошо показано, почему встроенных функций difflib
не всегда достаточно и почему приведённые выше функции могут работать лучше.
Отладка
Довольно много библиотек отладки и устранения неполадок также обеспечивают превосходные возможности по сравнению со стандартными библиотеками. Одной из таких библиотек является stackprinter
, которая предоставляет более полезные версии встроенных сообщений об исключениях Python:
# pip install stackprinter
import stackprinter
stackprinter.set_excepthook(style='darkbg2')
def do_stuff():
some_var = "data"
raise ValueError("Some error message")
do_stuff()
Всё, что вам нужно сделать, чтобы использовать её, это импортировать её и установить ловушку исключения. Затем запуск кода, выдающего исключение, приведёт к следующему:
Это большое улучшение, потому что оно показывает локальные переменные и контекст — то, для чего вам понадобится интерактивный отладчик. Ознакомьтесь с документацией , чтобы узнать о дополнительных параметрах, таких как интеграция с логированием или различные цветовые темы.
stackprinter
помогает с отладкой проблем, которые приводят к исключениям, но это лишь небольшая часть проблем, которые мы все отлаживаем. В большинстве случаев поиск и устранение ошибок включает в себя просто размещение операторов print
or log
по всему коду, чтобы увидеть текущее состояние переменных или был ли запущен код. И есть библиотека, которая может улучшить отладку print
в базовом стиле:
# pip install icecream
from icecream import ic
def do_stuff():
some_var = "data"
some_list = [1, 2, 3, 4]
ic()
return some_var
ic(do_stuff())
# ic| examples.py:46 in do_stuff() at 11:27:44.604
# ic| do_stuff(): 'data'
Она называется icecream
и предоставляет функцию ic
, которая служит заменой print
. Вы можете использовать простой код ic()
(без аргументов), чтобы проверить, какие части кода были выполнены. В качестве альтернативы вы можете использовать ic(some_func(...))
, которая будет выводить функцию/выражение вместе с возвращаемым значением.
Дополнительные параметры и настройки см. в GitHub README .
Тестирование
Говоря об отладке, мы также должны упомянуть тестирование. Я не собираюсь советовать вам использовать другие тестовые фреймворки вместо встроенных unittest
(даже если они просто лучше), вместо этого я хочу показать вам три небольших полезных инструмента:
Первая — это библиотека freezegun
, которая позволяет вам тестировать datetime
:
# pip install pytest freezegun
from freezegun import freeze_time
import datetime
# Run 'pytest' in shell
@freeze_time("2022-04-09")
def test_datetime():
assert datetime.datetime.now() == datetime.datetime(2022, 4, 9) # Passes!
def test_with():
with freeze_time("Apr 9th, 2022"):
assert datetime.datetime.now() == datetime.datetime(2022, 4, 9) # Passes!
@freeze_time("Apr 9th, 2022", tick=True)
def test_time_ticking():
assert datetime.datetime.now() > datetime.datetime(2022, 4, 9) # Passes!
Всё, что вам нужно сделать, это добавить декоратор к функции test
, которая устанавливает дату (или datetime
). Кроме того, вы также можете использовать её в качестве диспетчера контекста ( оператор with
).
Выше вы также можете увидеть, что она позволяет указать дату в удобном формате. И, наконец, вы также можете передать tick=True
, что перезапустит время с заданного значения.
При желании, если вы используете pytest
, вы также можете установить pytest-freezegun
для фикстур в стиле Pytest.
Второй важной библиотекой/помощником для тестирования, который вам нужен, является dirty-equals
. Она предоставляет вспомогательные функции равенства для сравнения вещей, которые вроде как равны:
# pip install dirty-equals
from dirty_equals import IsApprox, IsNow, IsJson, IsPositiveInt, IsPartialDict, IsList, AnyThing
from datetime import datetime
assert 1.0 == IsApprox(1)
assert 123 == IsApprox(120, delta=4) # close enough...
now = datetime.now()
assert now == IsNow # just about...
assert '{"a": 1, "b": 2}' == IsJson
assert '{"a": 1}' == IsJson(a=IsPositiveInt)
assert {'a': 1, 'b': 2, 'c': 3} == IsPartialDict(a=1, b=2) # Validate only subset of keys/values
assert [1, 2, 3] == IsList(1, AnyThing, 3)
Выше приведён пример помощников, которые проверяют, являются ли два целых числа или datetime
s примерно одинаковыми; является ли что-то допустимым JSON, включая тестирование отдельных ключей в этом JSON, или является ли значение словарём или списком с определёнными ключами/значениями.
И, наконец, третья полезная библиотека называется pyperclip
. Она предоставляет функции для копирования и вставки в/из буфера обмена. Я нахожу это очень полезным для отладки, например, для копирования значений переменных или сообщений об ошибках в буфер обмена, но у этого может быть много других вариантов использования:
# pip install pyperclip
# sudo apt-get install xclip
import pyperclip
try:
print("Do something that throws error...")
raise SyntaxError("Something went wrong...")
except Exception as e:
pyperclip.copy(str(e))
# CTRL+V -> Something went wrong...
В этом фрагменте мы используем автоматическое копирование сообщения об исключении в буфер обмена pyperclip.copy
, чтобы нам не приходилось копировать его вручную из результата программы.
CLI
Последняя категория, заслуживающая упоминания, — инструменты CLI. Если вы создаёте приложения CLI на Python, вы можете найти хорошее применение tqdm
. Эта небольшая библиотека предоставляет индикатор выполнения для ваших программ:
# pip install tqdm
from tqdm import tqdm, trange
from random import randint
from time import sleep
for i in tqdm(range(100)):
sleep(0.05) # 50ms per iteration
# 0% | | 0/100 [00:00<?, ?it/s]
# 100%|██████████| 100/100 [00:05<00:00, 19.95it/s]
with trange(100) as t:
for i in t:
t.set_description('Step %i' % i)
t.set_postfix(throughput=f"{randint(100, 999)/100.00}Mb/s", task=i)
sleep(0.05)
# Step 60: 60%|██████ | 60/100 [00:03<00:02, 19.78it/s, task=60, throughput=4.06Mb/s]
Чтобы использовать её, мы заключаем цикл в tqdm
и получаем индикатор выполнения в выводе программы. В более сложных случаях вы можете использовать диспетчер контекста trange
и установить дополнительные параметры, такие как описание или любые настраиваемые поля индикатора выполнения, такие как пропускная способность или истёкшее время.
Модуль также может быть запущен как команда оболочки ( python -m tqdm
), что может быть полезно, например, при создании резервной копии tar
или поиске файлов с расширением find
.
Дополнительные примеры и такие моменты, как интеграция с Pandas или Jupyter Notebook, см. в документации .
Заключение
С Python вы всегда должны искать существующие библиотеки, прежде чем внедрять что-либо с нуля. Если вы не создаёте особенно необычное или индивидуальное решение, скорее всего, кто-то уже создал его и выложил в PyPI.
В этой статье я перечислил только библиотеки общего назначения, которыми может воспользоваться каждый, но есть и много других специализированных, например, для машинного обучения или веб-разработки. Я бы порекомендовал вам заглянуть на https://github.com/vinta/awesome-python , где есть обширный список интересных библиотек, или вы также можете просто поискать PyPI по категориям , и я уверен, что вы найдёте там что-то полезное!