Python functools partial args

Введение в Python Functools

Python – высокоуровневый объектно-ориентированный язык программирования. Одно из самых больших преимуществ Python заключается в том, что в нем есть специальный функционал, который позволяет писать переиспользуемый код с помощью встроенных инструментов языка.

Functools – это библиотека Python, которая предназначена для работы с функциями высшего порядка. Такие функции могут принимать в себя другие функции и возвращать функции. Они помогают разработчиком писать код, который можно переиспользовать. Функции можно использовать или расширять, не переписывая их полностью. Модуль functools в Python предоставляет различные инструменты, которые позволяют добиться описанного эффекта. Например, следующие:

Функция partial в Python

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

Мы можем создавать новые функции, передавая частичные аргументы. Также мы можем заморозить некоторые аргументы функции, что приведет к появлению нового объекта. Еще один способ представить partial, заключается в том, что с ее помощью мы можем создать функцию со значениями по умолчанию. Partial поддерживает ключевые слова и позиционные аргументы в качестве фиксированных.
Давайте разберемся на примерах.

Как создать функцию partial?

Чтобы создать partial-функцию, используйте partial() из библиотеки functools. Пишется она следующим образом:

partial(func, /, *args, ** kwargs)

Так вы создадите partial функцию, которая вызовет func, передав ей фиксированные ключевые слова и позиционные аргументы. Здесь обычно передаются несколько необходимых аргументов для вызова функции func. Остальные аргументы передаются в *args и **kwargs.

Допустим, функция ниже складывает два числа:

def multiply(x, y): return x * y

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

def multiply(x, y): return x * y def doubleNum(x): return multiply(x, 2) def tripleNum(x): return multiply(x, 3)

Когда сценария работы функции всего 2-3, конечно, логичнее сделать, как показано выше. Но когда нужно написать еще 100 таких функций, то смысла переписывать один и тот же код столько раз нет. Здесь нам и пригодятся partial функции. Чтобы ими воспользоваться, во-первых, нам нужно импортировать partial из Functools.

from functools import partial def multiply(x, y): return x * y doubleNum = partial(multiply, 2) tripleNum = partial(multiply, 3) Print(doubleNum(10)) Output: 20

Как видно из примера, значения по умолчанию будут заменены переменными слева. Вместо x будет 2, а вместо y будет 10 при вызове doubleNum(10). В этом примере порядок не будет иметь принципиального значения, но в других вариантах использования он может иметь значение. Давайте рассмотрим пример на этот случай, чтобы понять порядок замены переменных.

from functools import partial def orderFunc(a,b,c,d): return a*4 + b*3 + c*2 + d result = partial(orderFunc,5,6,7) print(result(8)) Output: 60

Полное упорядочивание

У нас появилась функция orderFunc() , в которой происходит умножение a на 4, b на 3, c на 2 и добавление d к сумме значений.

Читайте также:  Экспорт txt в html

Мы создали partial функцию result() , которая вызывает orderFunc() со значениями 5, 6 и 7. Теперь значения 5, 6 и 7 будут заменять переменные a , b и c соответственно. На место переменной d встанет 8, так как она передается при вызове result() . В результате получится (4*5 + 6*3 + 7*2 + 8) = 60.

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

from functools import partial def orderFunc(a,b,c,d): return a*4 + b*3 + c*2 + d result = partial(orderFunc,c=5,d=6) print(result(8,4)) Output: 60

Здесь мы зафиксировали значение 5 за переменной c и 6 за переменной d . Вместо переменных a и b встанут значения 8 и 4. В результате получится (8*4+4*3+5*2+6) = 60.

Partial функцию можно определить в цикле и использовать для повторяющихся вычислений. Давайте рассмотрим пример:

from functools import partial def add(x,y): return x + y add_partials = [] for i in range (1, 10): function = partial(add, i) add_partials.append(function) print('Sum of <> and 2 is <>'.format(i,add_partials[i-1](2))) Output: Sum of 1 and 2 is 3 Sum of 2 and 2 is 4 Sum of 3 and 2 is 5 Sum of 4 and 2 is 6 Sum of 5 and 2 is 7 Sum of 6 and 2 is 8 Sum of 7 and 2 is 9 Sum of 8 and 2 is 10 Sum of 9 and 2 is 11

В этом примере мы будем суммировать определенный диапазон значений с 2, переиспользуя имеющуюся функцию. Мы можем вызвать partial в цикле и использовать ее функционал для вычисления сумм. Как видно из значений на выходе, у нас есть цикл от 1 до 10 и все значения в этом промежутке прибавляются к 2 с помощью функции partial, которая вызывает функцию сложения.

Метаданные

Несмотря на то, что partial функции являются независимыми, они хранят память (метаданные) функции, которую они расширяют.

Читайте также:  Javascript работа с изображением

from functools import partial def add(x,y): return x + y # create a new function that multiplies by 2 result = partial(add,y=5) print(result.func) print(result.keywords) Output:

Первый вызов func передаст имя функции и ее адрес в памяти, а второй вызов с keywords передаст ключевые слова в функцию. Таким образом функции partial можно назвать самодокументирующимися с помощью метаданных, которые они получают от расширяемой функции.

update_wrapper для partial

Мы можем обновлять метаданные функции с помощью другого инструмента из functools. Update_wrapper – это инструмент, который можно использовать для обновления метаданных функции. Давайте разберемся с ним на примере.

def multiply(x, y): """Test string.""" return x * y result = functools.partial(multiply, y=2) try: print ('Function Name:'+result.__name__) except AttributeError: print('Function Name: __no name__') print ('Function Doc:'+result.__doc__) print('Updating wrapper:') functools.update_wrapper(result, multiply) print ('Function Name:'+result.__name__) print ('Function Doc:'+result.__doc__) Output: Function Name: __no name__ Function Doc:partial(func, *args, **keywords) - new function with partial application of the given arguments and keywords. Updating wrapper: Function Name: multiply Function Doc: Test string.

Теперь как видно из выходных данных, до использования обертки (wrapper) у функции не было закрепленного за ней имени или документа. Как только мы обновили name и doc функции с помощью update_wrapper , в выводе увидели соответствующий результат.

Заключение

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

Источник

Модуль functools

Python 3 логотип

Модуль functools — сборник функций высокого уровня: взаимодействующих с другими функциями или возвращающие другие функции.

Модуль functools определяет следующие функции:

functools.cmp_to_key(func) — превращает функцию сравнения в key-функцию. Используется с инструментами, принимающие key-функции (sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()). Эта функция в основном используется в качестве переходного инструмента для программ, преобразованных из Python 2, которые поддерживали использование функций сравнения.

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

@functools.lru_cache(maxsize=128, typed=False) — декоратор, который сохраняет результаты maxsize последних вызовов. Это может сэкономить время при дорогих вычислениях, если функция периодически вызывается с теми же аргументами.

Читайте также:  Kotlin sort map by key

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

Если maxsize установлен в None, кэш может возрастать бесконечно. Также функция наиболее эффективна, если maxsize это степень двойки.

Если typed — True, аргументы функции с разными типами будут кэшироваться отдельно. Например, f(3) и f(3.0) будут считаться разными вызовами, возвращающие, возможно, различный результат.

Чтобы помочь измерить эффективность кэширования и отрегулировать размер кэша, обёрнутая функция дополняется функцией cache_info(), возвращающая namedtuple, показывающий попадания в кэш, промахи, максимальный размер и текущий размер. В многопоточном окружении, количество попаданий и промахов приблизительно.

Также имеется функция cache_clear() для очистки кэша.

Оригинальная функция доступна через атрибут __wrapped__.

@functools.total_ordering — декоратор класса, в котором задан один или более методов сравнения. Этот декоратор автоматически добавляет все остальные методы. Класс должен определять один из методов __lt__(), __le__(), __gt__(), или __ge__(). Кроме того, он должен определять метод __eq__().

functools.partial(func, *args, **keywords) - возвращает partial-объект (по сути, функцию), который при вызове вызывается как функция func, но дополнительно передают туда позиционные аргументы args, и именованные аргументы kwargs. Если другие аргументы передаются при вызове функции, то позиционные добавляются в конец, а именованные расширяют и перезаписывают.
  functools.reduce(function, iterable[, initializer]) - берёт два первых элемента, применяет к ним функцию, берёт значение и третий элемент, и таким образом сворачивает iterable в одно значение. Например, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) эквивалентно ((((1+2)+3)+4)+5). Если задан initializer, он помещается в начале последовательности.

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) — обновляет функцию-оболочку, чтобы она стала похожей на обёрнутую функцию. assigned — кортеж, указывающий, какие атрибуты исходной функции копируются в функцию-оболочку (по умолчанию это WRAPPER_ASSIGNMENTS (__name__, __module__, __annotations__ и __doc__)). updated — кортеж, указывающий, какие атрибуты обновляются (по умолчанию это WRAPPER_UPDATES (обновляется __dict__ функции-оболочки)).

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES) — удобная функция для вызова partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) как декоратора при определении функции-оболочки. Например:

Для вставки кода на Python в комментарий заключайте его в теги

Источник

Оцените статью