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

functools.md

217 строк · 19.1 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.3/library/functools.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 10.2. [`functools`](https://python-all.ru/3.3/library/functools.html#module-functools) – Функции высшего порядка и операции с вызываемыми объектами89**Исходный код:** [Lib/functools.py](https://python-all.ru/src/3.3/Lib/functools.py)1011---1213Модуль [`functools`](https://python-all.ru/3.3/library/functools.html#module-functools) предназначен для функций высшего порядка: функций, которые действуют на другие функции или возвращают их. В общем случае любой вызываемый объект может рассматриваться как функция для целей этого модуля.1415Модуль [`functools`](https://python-all.ru/3.3/library/functools.html#module-functools) определяет следующие функции:1617#### `functools.cmp_to_key(func)`1819Преобразует функцию сравнения старого образца в ключевую функцию. Используется с инструментами, которые принимают ключевые функции (такими как [`sorted()`](https://python-all.ru/3.3/library/functions.html#sorted), [`min()`](https://python-all.ru/3.3/library/functions.html#min), [`max()`](https://python-all.ru/3.3/library/functions.html#max), [`heapq.nlargest()`](https://python-all.ru/3.3/library/heapq.html#heapq.nlargest), [`heapq.nsmallest()`](https://python-all.ru/3.3/library/heapq.html#heapq.nsmallest), [`itertools.groupby()`](https://python-all.ru/3.3/library/itertools.html#itertools.groupby)). Эта функция в основном используется как средство перехода для программ, переносимых с Python 2, в котором поддерживались функции сравнения.2021Функция сравнения – это любой вызываемый объект, который принимает два аргумента, сравнивает их и возвращает отрицательное число для случая «меньше», ноль для равенства или положительное число для случая «больше». Ключевая функция – это вызываемый объект, который принимает один аргумент и возвращает другое значение, указывающее позицию в желаемой последовательности сортировки.2223Пример:2425```python26sorted(iterable, key=cmp_to_key(locale.strcoll))  # порядок сортировки с учётом локали27```2829Новое в версии 3.2.3031#### `@functools.lru_cache(maxsize=128, typed=False)`3233Декоратор для обёртывания функции запоминающим вызываемым объектом, который сохраняет до *maxsize* последних вызовов. Это может сэкономить время, когда дорогостоящая или связанная с вводом-выводом функция периодически вызывается с одними и теми же аргументами.3435Поскольку для кеширования результатов используется словарь, позиционные и именованные аргументы функции должны быть хешируемыми.3637Если *maxsize* установлен в None, механизм LRU отключается, и кэш может расти без ограничений. Механизм LRU работает лучше всего, когда *maxsize* является степенью двойки.3839Если *typed* установлен в True, аргументы функций разных типов будут кэшироваться отдельно. Например, `f(3)` и `f(3.0)` будут считаться разными вызовами с разными результатами.4041Чтобы оценить эффективность кэша и настроить параметр *maxsize*, обёрнутая функция оснащается функцией `cache_info()`, которая возвращает [*именованный кортеж*](https://python-all.ru/3.3/glossary.html#term-named-tuple), показывающий *попаданий*, *промахов*, *maxsize* и *currsize*. В многопоточной среде попадания и промахи являются приблизительными.4243Декоратор также предоставляет функцию `cache_clear()` для очистки или инвалидации кэша.4445Исходная базовая функция доступна через атрибут `__wrapped__`. Это полезно для интроспекции, обхода кэша или переоборачивания функции другим кэшем.4647Кэш [LRU (least recently used – вытеснение давно неиспользуемых)](https://python-all.ru/3.3/library/functools.html) работает наилучшим образом, когда самые последние вызовы являются лучшими предикторами будущих вызовов (например, самые популярные статьи на новостном сервере имеют тенденцию меняться каждый день). Ограничение размера кэша гарантирует, что он не будет бесконечно расти в долго работающих процессах, таких как веб-серверы.4849Пример LRU-кэша для статического веб-контента:5051```python52@lru_cache(maxsize=32)53def get_pep(num):54    'Retrieve text of a Python Enhancement Proposal'55    resource = 'http://www.python.org/dev/peps/pep-%04d/' % num56    try:57        with urllib.request.urlopen(resource) as s:58            return s.read()59    except urllib.error.HTTPError:60        return 'Not Found'6162>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:63...     pep = get_pep(n)64...     print(n, len(pep))6566>>> get_pep.cache_info()67CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)68```6970Пример эффективного вычисления [чисел Фибоначчи](https://python-all.ru/3.3/library/functools.html) с использованием кэша для реализации техники [динамического программирования](https://python-all.ru/3.3/library/functools.html):7172```python73@lru_cache(maxsize=None)74def fib(n):75    if n < 2:76        return n77    return fib(n-1) + fib(n-2)7879>>> [fib(n) for n in range(16)]80[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]8182>>> fib.cache_info()83CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)84```8586Новое в версии 3.2.8788Изменено в версии 3.3: Добавлена опция *typed*.8990#### `@functools.total_ordering`9192Для класса, определяющего один или несколько методов расширенного сравнения, этот декоратор класса предоставляет остальные. Это упрощает задачу определения всех возможных операций расширенного сравнения:9394Класс должен определить один из методов: [`__lt__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__lt__), [`__le__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__le__), [`__gt__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__gt__) или [`__ge__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__ge__). Кроме того, класс должен предоставлять метод [`__eq__()`](https://python-all.ru/3.3/reference/datamodel.html#object.__eq__).9596Например:9798```python99@total_ordering100class Student:101    def __eq__(self, other):102        return ((self.lastname.lower(), self.firstname.lower()) ==103                (other.lastname.lower(), other.firstname.lower()))104    def __lt__(self, other):105        return ((self.lastname.lower(), self.firstname.lower()) <106                (other.lastname.lower(), other.firstname.lower()))107```108109Новое в версии 3.2.110111#### `functools.partial(func, *args, **keywords)`112113Возвращает новый объект [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial), который при вызове будет вести себя как *func*, вызванная с позиционными аргументами *args* и именованными аргументами *keywords*. Если в вызов передаётся больше аргументов, они добавляются к *args*. Если передаются дополнительные именованные аргументы, они расширяют и переопределяют *keywords*. Примерно эквивалентно:114115```python116def partial(func, *args, **keywords):117    def newfunc(*fargs, **fkeywords):118        newkeywords = keywords.copy()119        newkeywords.update(fkeywords)120        return func(*(args + fargs), **newkeywords)121    newfunc.func = func122    newfunc.args = args123    newfunc.keywords = keywords124    return newfunc125```126127[`partial()`](https://python-all.ru/3.3/library/functools.html#functools.partial) используется для частичного применения функции, которое «замораживает» некоторую часть аргументов и/или ключевых слов функции, создавая новый объект с упрощённой сигнатурой. Например, [`partial()`](https://python-all.ru/3.3/library/functools.html#functools.partial) можно использовать для создания вызываемого объекта, который ведёт себя как функция [`int()`](https://python-all.ru/3.3/library/functions.html#int), где аргумент *base* по умолчанию равен двум:128129```python130>>> from functools import partial131>>> basetwo = partial(int, base=2)132>>> basetwo.__doc__ = 'Convert base 2 string to an int.'133>>> basetwo('10010')13418135```136137#### `functools.reduce(function, iterable[, initializer])`138139Применяет *function* с двумя аргументами последовательно к элементам *sequence* слева направо, сводя последовательность к одному значению. Например, `reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])` вычисляет `((((1+2)+3)+4)+5)`. Левый аргумент, *x*, является накопленным значением, а правый аргумент, *y*, – обновляемым значением из *sequence*. Если присутствует необязательный *initializer*, он помещается перед элементами последовательности в вычислении и служит значением по умолчанию, когда последовательность пуста. Если *initializer* не задан и *sequence* содержит только один элемент, возвращается первый элемент.140141Эквивалентно следующему:142143```python144def reduce(function, iterable, initializer=None):145    it = iter(iterable)146    if initializer is None:147        value = next(it)148    else:149        value = initializer150    for element in it:151        value = function(value, element)152    return value153```154155#### `functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)`156157Обновляет функцию-*обёртку* так, чтобы она выглядела как *обёрнутая* функция. Необязательные аргументы – кортежи, определяющие, какие атрибуты исходной функции напрямую присваиваются соответствующим атрибутам функции-обёртки и какие атрибуты функции-обёртки обновляются соответствующими атрибутами исходной функции. Значения по умолчанию для этих аргументов – константы уровня модуля *WRAPPER\_ASSIGNMENTS* (которая присваивает функции-обёртке атрибуты *\_\_name\_\_*, *\_\_module\_\_*, *\_\_annotations\_\_* и *\_\_doc\_\_*, т.е. строку документации) и *WRAPPER\_UPDATES* (которая обновляет у функции-обёртки атрибут *\_\_dict\_\_*, т.е. словарь экземпляра).158159Чтобы обеспечить доступ к исходной функции для интроспекции и других целей (например, для обхода кеширующего декоратора, такого как [`lru_cache()`](https://python-all.ru/3.3/library/functools.html#functools.lru_cache)), эта функция автоматически добавляет атрибут \_\_wrapped\_\_ к обёртке, который ссылается на исходную функцию.160161Основное назначение этой функции – использование в [*decorator*](https://python-all.ru/3.3/glossary.html#term-decorator)-функциях, которые оборачивают декорированную функцию и возвращают обёртку. Если функция-обёртка не обновляется, метаданные возвращаемой функции будут отражать определение обёртки, а не исходной функции, что обычно не очень полезно.162163[`update_wrapper()`](https://python-all.ru/3.3/library/functools.html#functools.update_wrapper) может использоваться с вызываемыми объектами, не являющимися функциями. Любые атрибуты, указанные в *assigned* или *updated*, отсутствующие у обёртываемого объекта, игнорируются (т.е. эта функция не будет пытаться установить их у функции-обёртки). [`AttributeError`](https://python-all.ru/3.3/library/exceptions.html#AttributeError) по-прежнему возбуждается, если сама функция-обёртка не имеет каких-либо атрибутов, указанных в *updated*.164165Новое в версии 3.2: Автоматическое добавление атрибута `__wrapped__`.166167Новое в версии 3.2: Копирование атрибута `__annotations__` по умолчанию.168169Изменено в версии 3.2: Отсутствующие атрибуты больше не вызывают [`AttributeError`](https://python-all.ru/3.3/library/exceptions.html#AttributeError).170171#### `@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)`172173Это удобная функция для вызова `partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)` в качестве декоратора функции при определении функции-обёртки. Например:174175```python176>>> from functools import wraps177>>> def my_decorator(f):178...     @wraps(f)179...     def wrapper(*args, **kwds):180...         print('Calling decorated function')181...         return f(*args, **kwds)182...     return wrapper183...184>>> @my_decorator185... def example():186...     """докстринг"""187...     print('Called example function')188...189>>> example()190Calling decorated function191Called example function192>>> example.__name__193'example'194>>> example.__doc__195'Docstring'196```197198Без использования этой фабрики декораторов имя примерной функции было бы `'wrapper'`, а строка документации исходной `example()` была бы потеряна.199200## 10.2.1. [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial) Объекты201202[`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial) объекты – это вызываемые объекты, создаваемые с помощью [`partial()`](https://python-all.ru/3.3/library/functools.html#functools.partial). Они имеют три атрибута только для чтения:203204#### `partial.func`205206Вызываемый объект или функция. Вызовы объекта [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial) будут перенаправлены к [`func`](https://python-all.ru/3.3/library/functools.html#functools.partial.func) с новыми аргументами и ключевыми словами.207208#### `partial.args`209210Крайние слева позиционные аргументы, которые будут добавлены в начало позиционных аргументов, передаваемых при вызове объекта [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial).211212#### `partial.keywords`213214Ключевые аргументы, которые будут предоставлены, когда объект [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial) будет вызван.215216Объекты [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial) похожи на объекты `function` в том, что они являются вызываемыми, могут быть слабыми ссылками и могут иметь атрибуты. Есть несколько важных отличий. Например, атрибуты `__name__` и `__doc__` не создаются автоматически. Кроме того, объекты [`partial`](https://python-all.ru/3.3/library/functools.html#functools.partial), определённые в классах, ведут себя как статические методы и не превращаются в связанные методы при поиске атрибутов экземпляра.217