Share This
Связаться со мной
Крути в низ
Categories
//Functools: улучшаем функции Python

Functools: улучшаем функции Python

03.10.2021Category : Python

База языка программирования Python на самом деле довольно обширна и включает в себя множество отличных инструментов для решения различных задач программирования. И многие из этих инструментов заслуживают отдельную статью для их рассмотрения и изучения. Модуль functools — как раз такой инструмент.

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

Кэширование вычислений

Вероятно, самая крутая вещь, которую предоставляет модуль functools, это возможность кэшировать определенные вычисления внутри памяти, а не выбрасывать их и потом тратить время на пересчет.

Это отличный способ сэкономить время вычисления. Особенно — если у вас идут таймауты и вы не можете интерпретировать свой код. Правда, кэширование связано с использованием значительно большего объема памяти, но в определенных ситуациях это оправданно.

Сам по себе язык программирования Python довольно декларативен. Обычно все управление памятью берет на себя интерпретатор. Хотя это и менее эффективный метод программирования, он избавляет нас от множества проблем с выделением памяти и прочими подобными вещами. Используя модуль functools, мы можем несколько изменить этот порядок, определив, что попадет в стек, а что будет пересчитано самостоятельно.

Что хорошо в кэшировании, которое обеспечивает модуль functools, так это простота в использовании и при этом лучший контроль за работой интерпретатора.

Воспользоваться этой замечательной функцией очень просто. Достаточно просто поместить ее над своей функцией в виде декоратора.

functools uluchshaem funkcii python 1bbe61b - Functools: улучшаем функции Python

Марк Лутц «Изучаем Python»

Скачивайте книгу у нас в телеграм

Скачать ×

Кэширование при вычислении факториала

Этот пример, как нам кажется, в полной мере демонстрирует преимущества кэширования.

У нас есть функция:

def factorial(n):     return n * factorial(n-1) if n else 1

Чтобы использовать кэширование, мы импортируем функцию lru_cache из модуля functools и вызовем ее перед нашей функцией:

from functools import lru_cache @lru_cache def factorial(n):     return n * factorial(n-1) if n else 1

Теперь давайте оценим выгоду, которую мы получим от применения данной функции. Сначала посмотрим, за какое время будет вычисляться факториал без кэширования:

functools uluchshaem funkcii python 04085f1 - Functools: улучшаем функции Python

Теперь перезагрузим ядро блокнота Jupyter и запустим нашу функцию факториала вместе с lru_cache:

functools uluchshaem funkcii python a412f19 - Functools: улучшаем функции Python

Уже на данном примере мы видим большую выгоду от применения данной техники кэширования.

Факториалы, как известно, сложно считать на компьютере. В основном, потому что они — естественный математический пример рекурсии. Соответственно, расчет кумулятивных функций распределения для биноминального распределения может оказаться просто кошмаром. Вычисления факториалов настолько интенсивны, что зачастую базовая функция факториала, встроенная в язык программирования, использует справочную таблицу, а не вычисляет число.

Таким образом, если вы собираетесь использовать ​​рекурсию, было бы неплохо познакомиться с модулем functools. Эта функция стандартной библиотеки может значительно ускорить вычисление ваших задач, которые обычно очень трудно решить на языке Python. В каком-то смысле это действительно возвращает нас к компилятору Numba Python, где один простой вызов может мгновенно ускорить ваш код.

«key»-функции

Случалась ли у вас ситуация, когда вы хотели бы использовать функцию из какого-нибудь старого кода, но она была скомпилирована как функция сравнения (функция с «cmp»-параметрами)? Этот тип функций уже особо не поддерживается и в современном Python 3 более не используется. Но при помощи модуля functools это проблему можно решить одним простым методом:

newfn = cmp_to_key(myfunction)

Функция partial

Функция partial() используется для частичного использования определенной функции. Часть аргументов этой функции «замораживается», в результате чего создается новый объект с упрощенной сигнатурой.

Код функции выглядит примерно так:

def partial(func, /, *args, **keywords):     def newfunc(*fargs, **fkeywords):         newkeywords = {**keywords, **fkeywords}         return func(*args, *fargs, **newkeywords)     newfunc.func = func     newfunc.args = args     newfunc.keywords = keywords     return newfunc

Создадим объект функции partial, используя при этом ту же функцию factorial, что и ранее.

from functools import partial fact = partial(factorial) fact(10)

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

Функция reduce

Функция reduce кумулятивно применяет функцию двух аргументов к итерируемой последовательности. Обратите внимание: последовательность непременно должна быть итерируемой.

Для данного примера мы будем использовать генератор списков range. Это позволит нам создать список практически любой длины.

from functools import reduce reduce(lambda x, y: x+y, range(1, 6))

Что этот код будет делать? Он сведет итерируемую последовательность к единственному значению в соответствии с указанной математической функцией.

В данном случае код вычислит сумму всех элементов последовательности. Это экономит время выполнения операций и просто удобно при написании кода.

Диспетчеризация

С помощью модуля functools в языке программирования Python может быть эффективно реализован алгоритм множественной диспетчеризации (multiple dispatch). А реализуется это простым добавлением декоратора.

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

@singledispatch def fun(arg, verbose=False):     if verbose:         print("Let me just say,", end=" ")     print(arg

А далее воспользуемся декоратором наша_функция.register, чтобы организовать диспетчеризацию для различных типов данных:

@fun.register def _(arg: int, verbose=False):     if verbose:         print("Strength in numbers, eh?", end=" ")     print(arg) @fun.register def _(arg: list, verbose=False):     if verbose:         print("Enumerate this:")     for i, elem in enumerate(arg):         print(i, elem)

Заключение

Functools — действительно отличный модуль! Более того, мы считаем, что этот модуль наверняка пригодится практически любому программисту на Python.

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

Практически все интересные вещи, которые вы можете захотеть сделать с вашими функциями, можно сделать при помощи модуля Functools, а это просто очень здорово!

Перевод статьи «FuncTools: An Underrated Python Package».

functools uluchshaem funkcii python b4d83b9 - Functools: улучшаем функции Python

Марк Лутц «Изучаем Python»

Скачивайте книгу у нас в телеграм

Скачать ×

  • 1 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2020 / All rights reserved

    Связаться со мной
    Close