20 малоизвестных фич и особенностей Python

8
17066
Добавить в избранное

Небольшая подборка полезных фич и особенностей Python, о которых вы, возможно, никогда не слышали.

20 малоизвестных фич и особенностей Python

У нас есть списки наиболее значимых проектов на Python. Но это достаточно глобальные обзоры, верно? Что ж, теперь посмотрите на фишки, которые значительно упростят вашу жизнь.

Отладка регулярных выражений

Регулярные выражения Python – мощный и полезный инструмент, но отлаживать их – то еще удовольствие. Оказывается, любую регулярку можно визуализировать в виде дерева синтаксического анализа. Эта возможность языка пока экспериментальная, за нее отвечает флаг re.DEBUG в методе re.compile.

Посмотрим на регулярное выражение для поиска тегов font. С ним что-то не так.

Теперь ясно, что именно. В закрывающем дескрипторе [/font] не экранированы квадратные скобки, поэтому он воспринимается не как тег, а как группа символов.

Выражения-генераторы

В Python есть очень удобные генераторы коллекций (списков, множеств, словарей), которые позволяют легко и быстро создавать отфильтрованные коллекции значений. Например, вот так можно создавать Python списки:

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

Ряд особенностей Python генераторов:

  • невозможно получить их длину;
  • нельзя сделать срез элементов, перемотать или получить случайный элемент по его индексу;
  • функция print выводит объект генератора, а не список элементов.

Зато их удобно использовать в различных конструкциях, где требуется итерируемый объект. В выражения-генераторы можно включать множественные условия отбора значений и сочетать несколько циклов:

Подводные камни дефолтных аргументов

Устанавливая значение аргументов функции по умолчанию, будьте очень осторожны:

Вряд ли вы хотели, чтобы список x изменялся при каждом вызове функции. Так происходит из-за того, что дефолтные параметры хранятся в неизменном кортеже в атрибуте foo.__defaults__, который создается в момент определения функции.

Вместо мутабельных списков лучше использовать значение None, а список присваивать в x уже внутри функции:

Передача значений в генератор

Язык программирования Python поддерживает генераторы – функции со множественными точками входа. В генератор можно передать значение на каждом шаге работы, что очень удобно, если приходится работать с динамическими данными:

Это бессмысленная в целом функция, которая просто сохраняет полученное значение и возвращает его при следующем вызове.

В старом стандарте языка был метод my_generator.next(value), который сразу возвращал текущее значение генератора и принимал новое. В Python 3 необходимо использовать два метода: next(my_generator) и my_generator.send(value).

Встроенная функция breakpoint()

Хотя мы и хотим писать идеальный код, правда в том, что это невозможно. Но такие фичи, как новая встроенная функция breakpoint(), пришедшая с Python 3.7, существенно облегчают жизнь питонистов. Нет, это не добавляет принципиально новой функциональности в язык программирования Python, зато делает дебагинг более гибким и понятным.

Шаг среза

Третий аргумент slice-оператора в Python определяет шаг среза. По умолчанию он равен единице, поэтому в итоговый срез попадают все элементы диапазона подряд.

А можно взять, например, каждый второй элемент:

Если передать третьим параметром -1, счет пойдет в обратном порядке. Так можно легко развернуть список или строку.

Декораторы

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

Теперь необходимо передать функции print_args другую функцию, аргументы которой необходимо распечатать:

Все работает правильно, но приходится создавать новую функцию и вызывать именно ее.

В Python работа с декораторами устроена гораздо удобнее. Вы можете сохранить исходное имя функции и ее подпись при интроспеции:

Отсутствующие элементы словарей

В Python 2.5 у словарей появился специальный метод __missing__. Он вызывается при обращении к отсутствующим элементам:

Примерно то же самое делает подкласс defaultdict: он вызывает для несуществующих элементов функцию без аргументов.

Многострочные регулярные выражения

Одна из самых приятных особенностей Python – возможность разбить длинные регулярки на несколько строк, добавить комментарии и сделать их более читаемыми.

Многострочные регулярные выражения Python можно создавать и без re.VERBOSE, используя обычную конкатенацию строчных литералов:

Кроме того, совпадения можно именовать:

Распаковка аргументов

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

Эта фича языка очень полезна, так как в Python списки, кортежи и словари широко используются в качестве контейнеров.

Динамическое создание типов

Программирование на Python допускает создание новых типов прямо во время выполнения программы.

Это то же самое, что и:

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

Метод словарей get

Если вы обратитесь к несуществующему ключу словаря dict[key], то получите исключение. Эту проблему можно решить с помощью метода dict.get(key), который вернет None для несуществующих ключей. Вторым параметром ему можно передать значение по умолчанию:

Это удобно, например, при арифметических операциях.

Дескрипторы

Атрибуты можно превратить в дескрипторы, изменив их стандартное поведение с помощью методов __get__, __set__ или __delete__. Таким образом можно, например, запретить перезапись или удаление свойства.

Создадим такой дескриптор, используя для удобства декоратор:

Теперь при обращении через точку к дескриптору foo, управление передается его методу __get__, который сначала печатает строчку с данными дескриптора, а затем вызывает его «родной» геттер (выполняется код функции foo).

Дескрипторы – довольно сложная фича, но вам стоит разобраться в ней, чтобы глубже понимать как работает язык программирования Python.

Doctest: документация + юнит-тестирование

Модуль doctest находит в коде фрагменты, похожие на интерактивные сессии, и выполняет их, чтобы проверить заявленный результат. Фактически, с его помощью можно создать «исполняемую документацию».

Вот официальный пример работы doctest:

Чтобы увидеть результат, запустите этот модуль прямо из командной строки с флагом -v. Вы получите нечто вроде:

Именованное форматирование строк

В Python 3 для форматирования строк используется метод format:

Передаваемые в строку параметры можно именовать для удобства:

Поиск модулей

Путь поиска импортируемых модулей в Python выглядит так:

  1. Домашний каталог программы, который может отличаться от текущего рабочего каталога
  2. Адреса из переменной окружения PYTHONPATH.
  3. Каталоги стандартной Python библиотеки, которые устанавливаются автоматически.
  4. Директории, перечисленные в *.pth файлах.
  5. Каталог site-packages, в котором автоматически размещаются все сторонние расширения.

try-except-else

В конструкцию try-except можно добавить также блок else. Он отработает только в случае выполнения кода без ошибок:

Использовать блок else предпочтительнее, чем добавлять дополнительный код в блок try. Это позволяет избежать случайного перехвата исключений, которые не были вызваны кодом, защищенным конструкцией try-except.

Ререйз исключений

Применив оператор raise без параметров внутри обработчика ошибок, вы можете повторно «поднять» пойманное исключение с сохранением его оригинальной трассировки стека. Это полезно, если пойманное исключение должно обрабатываться на верхних уровнях программы:

Оригинальную трассировку можно получить с помощью sys.exc_info().

Автодополнение для интерактивного интерпретатора

Одна из немногочисленных неприятных особенностей Python консоли: отсутствие встроенного автодополнения вводимых команд. Эту проблему решает модуль rlcompleter:

Теперь с помощью клавиши TAB вы можете быстро подобрать нужные атрибуты:

import this

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

Надеемся, вы узнали что-то новое о возможностях и особенностях Python. Своими открытиями делитесь в комментариях.

Лучшие материалы и книги по Python

Интересуетесь программированием на Python?

Подпишитесь на нашу рассылку, чтобы получать больше интересных материалов:

И не беспокойтесь, мы тоже не любим спам. Отписаться можно в любое время.




Комментариев: 8

  1. В Python3+ вместо foo.func_defaults используется foo.__defaults__

    1. Спасибо. Исправили 🙂

  2. Большое спасибо за статью! Очень много полезной информации!
    По-поводу форматирования строк, в Python 3.6 появился новый способ f-строки, который гибче, читабельней и быстрей. https://www.python.org/dev/peps/pep-0498

    Небольшая опечатка про срез:
    каждый второй элемент:
    print(a[2:8:]) # [3, 5, 7]
    правильно:
    print(a[2:8:2]) # [3, 5, 7]

    Спасибо.

    1. Спасибо за информацию и за внимательность 😉

  3. Nikolay Karelin

    Народ, не позорьтесь…

    Судя по упомянутой версии 2.5 вы перевели что-то старое… и фиг проверяли.

    Например from __future__ import braces давно выдает SyntaxError D)

    1. А вас не смутил long в разделе о доктестах?))

  4. Дэвид Хэллер

    print(a[2:8:]) # [3, 5, 7]
    Если передать третьим параметром -1, счет пойдет в обратном порядке. Так можно легко развернуть список или строку.

    Опечатка должно быть print(a[2:8:2]) # [3, 5, 7]

    1. Спасибо за внимательность)

Добавить комментарий