Документация Python неофициальный перевод
Содержание страницы

9.8. functools – Функции высшего порядка и операции с вызываемыми объектамиfunctools – Higher order functions and operations on callable objects

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

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

functools.partial(func, *args, **keywords)

Возвращает новый объект partial, который при вызове будет вести себя как func, вызванная с позиционными аргументами args и именованными аргументами keywords. Если в вызов передаётся больше аргументов, они добавляются к args. Если передаются дополнительные именованные аргументы, они расширяют и переопределяют keywords. Примерно эквивалентно:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

partial() используется для частичного применения функции, которое «замораживает» некоторую часть аргументов и/или ключевых слов функции, создавая новый объект с упрощённой сигнатурой. Например, partial() можно использовать для создания вызываемого объекта, который ведёт себя как функция int(), где аргумент base по умолчанию равен двум:

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
functools.reduce(function, iterable[, initializer])
Применяет function с двумя аргументами последовательно к элементам sequence слева направо, сводя последовательность к одному значению. Например, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) вычисляет ((((1+2)+3)+4)+5). Левый аргумент, x, является накопленным значением, а правый аргумент, y, – обновляемым значением из sequence. Если присутствует необязательный initializer, он помещается перед элементами последовательности в вычислении и служит значением по умолчанию, когда последовательность пуста. Если initializer не задан и sequence содержит только один элемент, возвращается первый элемент.
functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

Обновляет функцию-обёртку так, чтобы она выглядела как обёрнутая функция. Необязательные аргументы – кортежи, определяющие, какие атрибуты исходной функции напрямую присваиваются соответствующим атрибутам функции-обёртки и какие атрибуты функции-обёртки обновляются соответствующими атрибутами исходной функции. Значения по умолчанию для этих аргументов – константы уровня модуля WRAPPER_ASSIGNMENTS (которая присваивает функции-обёртке атрибуты __name__, __module__, __annotations__ и __doc__, т.е. строку документации) и WRAPPER_UPDATES (которая обновляет у функции-обёртки атрибут __dict__, т.е. словарь экземпляра).

Основное назначение этой функции – использование в decorator-функциях, которые оборачивают декорированную функцию и возвращают обёртку. Если функция-обёртка не обновляется, метаданные возвращаемой функции будут отражать определение обёртки, а не исходной функции, что обычно не очень полезно.

functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

Это удобная функция для вызова partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) в качестве декоратора функции при определении функции-обёртки. Например:

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print('Calling decorated function')
...         return f(*args, **kwds)
...     return wrapper
...
>>> @my_decorator
... def example():
...     """докстринг"""
...     print('Called example function')
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'

Без использования этой фабрики декораторов имя примерной функции было бы 'wrapper', а строка документации исходной example() была бы потеряна.

9.8.1. partial Объектыpartial Objects

partial объекты – это вызываемые объекты, создаваемые с помощью partial(). Они имеют три атрибута только для чтения:

partial.func
Вызываемый объект или функция. Вызовы объекта partial будут перенаправлены к func с новыми аргументами и ключевыми словами.
partial.args
Крайние слева позиционные аргументы, которые будут добавлены в начало позиционных аргументов, передаваемых при вызове объекта partial.
partial.keywords
Ключевые аргументы, которые будут предоставлены, когда объект partial будет вызван.

Объекты partial похожи на объекты function в том, что они являются вызываемыми, могут быть слабыми ссылками и могут иметь атрибуты. Есть несколько важных отличий. Например, атрибуты __name__ и __doc__ не создаются автоматически. Кроме того, объекты partial, определённые в классах, ведут себя как статические методы и не превращаются в связанные методы при поиске атрибутов экземпляра.