Статьи: Змеиные удобности
27.01.2018


В последние дни, поддавшись «эффекту Википедии», я прочитал много страниц документации Пайтона, посвящённых различным модулям из стандартной библиотеки. И, скажу вам, что их немало. На каждый чих и любой типичный use case есть свой готовый модуль. И в этом посте я хочу привести подборку некоторых не самых известных (на самом деле может быть просто я такой слоупок, что узнал о них только сейчас), но очень полезных модулей, которые помогут экономить время и силы вместо того, чтобы изобретать колесо заново. Надеюсь, кому-то эта информация окажется полезной, а то, если честно, я даже устал столько всего читать :(

Предполагается, что это пролонгированный пост, который будет периодически дополняться, пополняясь новыми ссылками и названиями. Следите за обновлениями в соцсетях (в частности, в ВК, Щебетаче и Телеграмме)!


re — регулярные выражения

Начнём с известнейшего модуля для работы с регулярными выражениями. Думаю, все о нём знают, поэтому я включил его сюда, только чтобы напомнить о необходимости чтения документации. По размеру она у него приличная, но реально полезная. Кто, например, знал, что можно отключить сохранение группы, если скобочки нужны исключительно для группировки выражений, с помощью вопросительного знака и двоеточия? Простой пример: тян(?:ка)?. Или что группы можно именовать? А про режим многословных (verbose) выражений, когда выражение можно дробить на строки и вписывать комментарии прямо в нём же? То-то же! Думаю, многие про них знают, но не могу не упомянуть и про опережающие и ретроспективные проверки, которые порой ну очень полезны.

Также отдельно отмечу, что питоновкий модуль из коробки умеет кэшировать скомпилированные выражения, а все функции, расположенные на уровне модуля, вызывают точно ту же компиляцию, что и явная функция compile. Так что если в программе используется всего несколько выражений (на данный момент _MAXCACHE = 512), то нет ничего страшного, если не сохранять результат их компиляции в переменную явно. В Java, например, так нельзя. Там компиляция выражения каждый раз выполняется заново, так что обязательно нужно куда-то сохранять её результат.


configparser — парсинг конфигурационных файлов

В состав KozConfigurator'а входят два скрипта, предназначенных для облегчения работы с Samba: ksharman.py и kremount.py, которые предназначены для изменения конфигурационных файлов Samba, чтоб «шарить» локальные папки и монтировать сетевые. Конфиги в них парсятся вручную регулярными выражениями. А в ksharman.py так ещё и написан целый класс для составления правильной структуры файла при перезаписи. Но, оказывается, всё это было зря, потому что уже есть готовый модуль для работы с конфигами в стиле *.ini-файлов! Он берёт на себя отображение секций, ключей и значений в обычные dict'оподобные объекты и предоставляет вспомогательные функции для преобразования типов. Модуль поддаётся настройке и пригоден для использования с многими похожими форматами файлов.


csv — текстовые таблицы

Модуль для работы с файлами в так называемом comma-separated values формате. Причём значения могут быть разделены не только запятыми, но и табуляциями. Модуль позволяет выбирать из нескольких форматов и отдельный акцент делается на работе с экспортированными из Microsoft Excel таблицами. Не припомню, чтоб мне нужно было работать с такими файлами, но вообще это очень распространённый формат, так что определённо рано или поздно модуль пригодится.


cmd — создаём свой командный интерпретатор

Другой пример модуля, помогающего избежать велосипедостроения. Возьмём мой недавний скрипт для подсчёта квадратных уравнений. Там я вручную зацикливал программу для организации ввода произвольного количества выражений. Оказывается, для этого тоже уже предусмотрен отдельный модуль! И пусть в моём случае переизобретённое колесо работает вполне неплохо, но в более сложных ситуациях, когда есть набор чётко определённых команд и необходимость вывода справочного сообщения по работе с программой, готовый модуль поможет не только спасти немного времени, но и позволит написать красивый код. Ну вот например:

import cmd


class Main(cmd.Cmd):
    intro = "Just a counter :3"
    prompt = "SadBot > "

    def __init__(self):
        super().__init__()
        self.counter = 0

    def do_inc(self, arg):
        """Increase the value of the counter."""
        
        self.counter += 1
        print(self.counter)

    def do_dec(self, arg):
        """Decrease the value of the counter."""

        self.counter -= 1
        print(self.counter)

    def do_set(self, arg):
        """Set the counter to a specified value."""

        try:
            self.counter = int(arg)
        except ValueError:
            print("Invalid value!")
        else:
            print(self.counter)

    def do_print(self, arg):
        """Print the value of the counter."""

        print(self.counter)

    def do_bye(self, arg):
        print("Bye!")
        exit()

if __name__ == "__main__":
    Main().cmdloop()

Скриншот с результатом выполнения программы


shutil — операции с файлами

Ещё одно моё недавнее открытие. Поскольку Python часто используется в *NIX'ах в качестве скриптового языка общего назначения, то там этот модуль может быть особенно полезен. Копирование, перемещение, удаление, архивирование и разархивирование файлов, изменение влацельца файла или прав доступа — это всё к нему.


pathlib — пути для людей

В последних версиях Python наконец-то завезли человеческие пути в виде полноценных объектов, прям как в Java 8. Так что можно больше не дёргать строки туда-сюда через модуль os.path! К тому же объекты путей поддерживают некоторые файловые операции вроде удаления, перемещения или переименования.

Небольшой пример. Как было:

import os
import shutil

path = os.path.join("dir1", "dir2", "file.txt")
if not os.path.exists(path):
    absolute_path = os.path.abspath(path)
    print('"%s" does not exist!' % path)
else:
    with open(path) as f:
        print(f.readline())
    new_path = os.path.join(os.path.dirname(path), "file2.txt")
    shutil.move(path, new_path)

Как стало (примерно):

from pathlib import Path

path = Path.cwd() / "dir1" / "dir2" / "file.txt"
if not path.exists():
    print('"%s" does not exist!' % path)
else:
    with path.open() as f:
        print(f.readline())
    path.rename("file2.txt")

К сожалению, последний пример будет работать лишь в последней на данный момент версии змеиного языка — Python 3.6. Несмотря на то, что модуль добавлен ещё в 3.4, полноценная поддержка во встроенных функциях появилась совсем недавно.


io.StringIO — StringBuilder

Как в Java, так и в Python строки — это неизменяемые объекты. Поэтому при каждой конкатенации создаётся новый объект, что не особо эффективно при динамическом создании строк, когда присоединений выполняется очень много. Для решения этой проблемы в Java есть отдельный класс StringBuilder. В Питоне его роль играет класс StringIO из модуля io. На самом деле прямое сравнение правильнее было бы проводить с классами stream'ов, но не суть.

Очень простой и тупой пример:

s = io.StringIO()
for c in "abcdef":
    s.write(c)
s.getvalue()

В модуле есть аналогичный класс для работы с байтами и ещё много других классов, используемых высокоуровневыми API. Например, при открытии файла в текстовом режиме функция open вернёт io.TextIOWrapper, а при открытии в режиме чтения байтов — io.BufferedReader.


array — массивы для упоротых

Пока не ушли далеко от низкоуровневых штук, упомяну, что в Пайтоне есть возможность создавать не только списки, но и обычные типизированные массивы. Вызывающее название пункта обусловлено тем, что я не знаю, зачем это может кому-то пригодиться. Наверное, для каких-то оптимизаций. Хотя я едва ли могу представить человека, который будет писать что-то, требующее хорошей производительности, на Питоне.


warnings — предупреждения

Кроме исключений, приводящих к завершению программы, если их никто не перехватывает, есть ещё такой зверь, как предупреждения. Функции модуля позволяют настроить, как предупреждения будут обрабатываться: игнорироваться, выводиться в stderr или же генерировать соответствующие исключения, завершая выполнение программы. Как и сообщения из модуля логирования (его, кстати, можно настроить на перехват всех предупреждений и превращение их в записи лога), предупреждения делятся на уровни по своей важности.

Думаю, иногда этот модуль может быть полезен.


pdb — отладчик

Последним на сегодня рассмотрим модуль отладчика. Вряд ли кто-то будет им пользоваться во время разработки (ведь отлаживать в IDE гораздо удобнее), но для общего развития и на случай, если кому-то придётся отлаживать код на продакшене (упаси господи, конечно!), упомянуть его стоит. Отладчик построен на основе другого модуля bdb, представляющего собой фреймворк для создания отладчиков. Но внутренняя кухня нам не особо интересна. Главное — что через отладчик можно запустить любой скрипт (python -m pdb my_script.py) и затем управлять выполнением программы, используя специальные команды, перечисленные в документации.