Spec-Zone.ru › Python 3.13

functools — Функции высшего порядка и операции над вызываемыми объектами

Исходный код: Lib/functools.py

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

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

@functools.cache(user_function)

Простая, лёгкая кэширующая функция без ограничений по размеру. Иногда её называют “мемоизацией”.

Возвращает то же, что и lru_cache(maxsize=None), создавая тонкий обёртку вокруг поиска в словаре по аргументам функции. Поскольку она никогда не нуждается в удалении старых значений, она меньше и быстрее, чем lru_cache() с ограничением по размеру.

Например:

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

>>> factorial(10)      # no previously cached result, makes 11 recursive calls
3628800
>>> factorial(5)       # just looks up cached value result
120
>>> factorial(12)      # makes two new recursive calls, the other 10 are cached
479001600

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

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

Добавлена в версии 3.9.

@functools.cached_property(func)

Преобразует метод класса в свойство, значение которого вычисляется один раз и затем кэшируется как обычное атрибут на протяжении всего жизненного цикла экземпляра. Аналогично property(), с добавлением кэширования. Полезно для дорогостоящих вычисляемых свойств экземпляров, которые в противном случае являются фактически неизменяемыми.

Пример:

class DataSet:

    def __init__(self, sequence_of_numbers):
        self._data = tuple(sequence_of_numbers)

    @cached_property
    def stdev(self):
        return statistics.stdev(self._data)

Механизм работы cached_property() несколько отличается от property(). Обычное свойство блокирует запись в атрибуты, если не определён сетер. В отличие от этого, cached_property разрешает записи.

Декоратор cached_property выполняется только при обращении и только когда атрибут с таким же именем не существует. Когда он выполняется, cached_property записывает в атрибут с тем же именем. Последующие чтение и запись атрибута имеют приоритет над методом cached_property, и он работает как обычный атрибут.

Кэшированное значение можно очистить, удалив атрибут. Это позволяет методу cached_property снова выполниться.

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

Обратите внимание, что этот декоратор мешает работе PEP 412 словарей совместного использования ключей. Это означает, что словари экземпляров могут занимать больше места, чем обычно.

Также этот декоратор требует, чтобы атрибут __dict__ каждого экземпляра был изменяемым отображением. Это означает, что он не будет работать с некоторыми типами, такими как метаклассы (так как атрибуты __dict__ экземпляров типа являются только для чтения прокси для пространства имён класса) и теми, которые задают __slots__ без включения __dict__ в качестве одного из определённых слотов (так как такие классы вообще не предоставляют атрибута __dict__).

Если изменяемое отображение недоступно или если требуется эффективное совместное использование ключей, аналогичный эффект cached_property() также можно получить, размещая property() поверх lru_cache(). Подробнее о том, чем это отличается от cached_property(), см. в Как кэшировать вызовы методов?.

Добавлена в версии 3.8.

Изменено в версии 3.12: До Python 3.12, cached_property включал недокументированную блокировку, чтобы гарантировать, что в многопоточной среде функция-получатель запускалась только один раз на экземпляр. Однако блокировка была на уровне свойства, а не экземпляра, что могло привести к неприемлемо высокому конфликту блокировок. В Python 3.12+ эта блокировка удалена.

functools.cmp_to_key(func)

Преобразует функцию сравнения старого стиля в функцию функцию ключа. Используется с инструментами, которые принимают функции ключа (такими как sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()). Данная функция в первую очередь используется как инструмент перехода для программ, которые конвертируются из Python 2, где использовались функции сравнения.

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

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

Пример:

sorted(iterable, key=cmp_to_key(locale.strcoll))  # locale-aware sort order

Примеры сортировки и краткий учебник по сортировке см. в Методы сортировки.

Добавлена в версии 3.2.

END_OF_DOCUMENT_MARKER
@functools.lru_cache(user_function)
@functools.lru_cache(maxsize=128, typed=False)

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

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

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

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

Разные шаблоны аргументов могут рассматриваться как отдельные вызовы с отдельными записями в кэше. Например, f(a=1, b=2) и f(b=2, a=1) отличаются порядком ключевых аргументов и могут иметь две отдельные записи в кэше.

Если указана user_function, она должна быть вызываемым объектом. Это позволяет применить декоратор lru_cache непосредственно к пользовательской функции, оставив maxsize по умолчанию 128:

@lru_cache
def count_vowels(sentence):
    return sum(sentence.count(vowel) for vowel in 'AEIOUaeiou')

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

Если typed установлено в true, аргументы функции разных типов будут кэшироваться отдельно. Если typed равно false, реализация обычно будет считать их эквивалентными вызовами и кэшировать только один результат. (Некоторые типы, такие как str и int, могут кэшироваться отдельно, даже если typed равно false.)

Обратите внимание, что специфичность типа применяется только к непосредственным аргументам функции, а не к их содержимому. Скалярные аргументы Decimal(42) и Fraction(42) будут рассматриваться как отдельные вызовы с отдельными результатами. В отличие от этого, кортежи аргументов ('answer', Decimal(42)) и ('answer', Fraction(42)) обрабатываются как эквивалентные.

Обернутая функция снабжена функцией cache_parameters() , которая возвращает новый dict , показывающий значения для maxsize и typed. Это для информационных целей. Изменение значений не оказывает никакого эффекта.

Для измерения эффективности кэша и настройки параметра maxsize обернутая функция снабжена функцией cache_info() , которая возвращает именованный кортеж , показывающий hits, misses, maxsize и currsize.

Декоратор также предоставляет функцию cache_clear() для очистки или аннулирования кэша.

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

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

Если метод кэшируется, аргумент экземпляра self включается в кэш. См. Как кэшировать вызовы методов?

Кэш LRU (Least Recently Used) работает лучше всего, когда самые последние вызовы являются лучшими предсказателями будущих вызовов (например, самые популярные статьи на новостном сервере, как правило, меняются каждый день). Ограничение размера кэша гарантирует, что кэш не будет расти без ограничений при длительных процессах, таких как веб-серверы.

Как правило, кэш LRU следует использовать только тогда, когда вы хотите повторно использовать ранее вычисленные значения. Соответственно, нет смысла кэшировать функции со побочными эффектами, функции, которые должны создавать различные изменяемые объекты при каждом вызове (например, генераторы и асинхронные функции), или нечистые функции, такие как time() или random().

Пример кэша LRU для статического веб-контента:

@lru_cache(maxsize=32)
def get_pep(num):
    'Retrieve text of a Python Enhancement Proposal'
    resource = f'https://peps.python.org/pep-{num:04d}'
    try:
        with urllib.request.urlopen(resource) as s:
            return s.read()
    except urllib.error.HTTPError:
        return 'Not Found'

>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
...     pep = get_pep(n)
...     print(n, len(pep))

>>> get_pep.cache_info()
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)

Пример эффективного вычисления чисел Фибоначчи с использованием кэша для реализации техники динамического программирования:

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

>>> [fib(n) for n in range(16)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

>>> fib.cache_info()
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

Добавлен в версии 3.2.

Изменено в версии 3.3: Добавлен параметр typed.

Изменено в версии 3.8: Добавлен параметр user_function.

Изменено в версии 3.9: Добавлена функция cache_parameters()

@functools.total_ordering

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

Класс должен определить один из __lt__(), __le__(), __gt__(), или __ge__(). Кроме того, класс должен обеспечить метод __eq__().

Например:

@total_ordering
class Student:
    def _is_valid_operand(self, other):
        return (hasattr(other, "lastname") and
                hasattr(other, "firstname"))
    def __eq__(self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        if not self._is_valid_operand(other):
            return NotImplemented
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))

Примечание

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

Примечание

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

Добавлен в версии 3.2.

Изменено в версии 3.4: Возвращение NotImplemented из основной функции сравнения для нераспознанных типов теперь поддерживается.

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

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

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

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
class functools.partialmethod(func, /, *args, **keywords)

Возвращает новый дескриптор partialmethod, который ведет себя как partial, за исключением того, что он предназначен для использования в качестве определения метода, а не для непосредственного вызова.

func должен быть дескриптором или вызываемым объектом (объекты, которые являются обоими, например обычные функции, обрабатываются как дескрипторы).

Когда func является дескриптором (таким как обычная Python-функция, classmethod(), staticmethod(), abstractmethod() или другой экземпляр partialmethod), вызовы __get__ делегируются базовому дескриптору, и возвращается соответствующий объект partial.

Когда func является вызываемым объектом, который не является дескриптором, динамически создается соответствующий связанный метод. Он ведет себя как обычная Python-функция при использовании в качестве метода: аргумент self будет вставлен как первый позиционный аргумент, даже перед аргументами args и keywords, переданными конструктору partialmethod.

Пример:

>>> class Cell:
...     def __init__(self):
...         self._alive = False
...     @property
...     def alive(self):
...         return self._alive
...     def set_state(self, state):
...         self._alive = bool(state)
...     set_alive = partialmethod(set_state, True)
...     set_dead = partialmethod(set_state, False)
...
>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True

Добавлен в версии 3.4.

functools.reduce(function, iterable, [initial, ]/)

Применяет функцию с двумя аргументами кумулятивно к элементам итерируемого объекта слева направо, чтобы свести итерируемый объект к одному значению. Например, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) вычисляет ((((1+2)+3)+4)+5). Левый аргумент, x, — это накопленное значение, а правый аргумент, y, — это обновляемое значение из итерируемого объекта. Если присутствует необязательный initial, он размещается перед элементами итерируемого объекта в вычислении и служит значением по умолчанию, когда итерируемый объект пуст. Если initial не задан и iterable содержит только один элемент, возвращается первый элемент.

Приблизительно эквивалентно:

initial_missing = object()

def reduce(function, iterable, initial=initial_missing, /):
    it = iter(iterable)
    if initial is initial_missing:
        value = next(it)
    else:
        value = initial
    for element in it:
        value = function(value, element)
    return value

См. itertools.accumulate() для итератора, который возвращает все промежуточные значения.

@functools.singledispatch

Преобразует функцию в функцию с однократным вызовом обобщенную функцию.

Для определения обобщенной функции используйте декоратор @singledispatch. При определении функции с помощью @singledispatch, обратите внимание, что диспетчеризация происходит по типу первого аргумента:

>>> from functools import singledispatch
>>> @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)

types.UnionType и typing.Union также могут быть использованы:

>>> @fun.register
... def _(arg: int | float, verbose=False):
...     if verbose:
...         print("Strength in numbers, eh?", end=" ")
...     print(arg)
...
>>> from typing import Union
>>> @fun.register
... def _(arg: Union[list, set], verbose=False):
...     if verbose:
...         print("Enumerate this:")
...     for i, elem in enumerate(arg):
...         print(i, elem)
...

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

>>> @fun.register(complex)
... def _(arg, verbose=False):
...     if verbose:
...         print("Better than complicated.", end=" ")
...     print(arg.real, arg.imag)
...

Для кода, который выполняет диспетчеризацию по типу коллекции (например, list), но хочет добавить подсказки типов к элементам коллекции (например, list[int]), тип диспетчеризации должен быть явно передан декоратору, а подсказка типа — в определение функции:

>>> @fun.register(list)
... def _(arg: list[int], verbose=False):
...     if verbose:
...         print("Enumerate this:")
...     for i, elem in enumerate(arg):
...         print(i, elem)

Примечание

Во время выполнения функция будет выполнять диспетчеризацию по экземпляру списка независимо от типа элементов в списке, т.е. [1,2,3] будет обработана так же, как ["foo", "bar", "baz"]. Аннотация, приведенная в этом примере, предназначена только для статических проверок типов и не оказывает влияния на выполнение.

Для регистрации лямбда-функций и имеющихся функций также можно использовать атрибут register() в функциональном виде:

>>> def nothing(arg, verbose=False):
...     print("Nothing.")
...
>>> fun.register(type(None), nothing)

Атрибут register() возвращает функцию без декоратора. Это позволяет использовать стекинг декораторов, pickling, и создавать модульные тесты для каждой реализации по отдельности:

>>> @fun.register(float)
... @fun.register(Decimal)
... def fun_num(arg, verbose=False):
...     if verbose:
...         print("Half of your number:", end=" ")
...     print(arg / 2)
...
>>> fun_num is fun
False

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

>>> fun("Hello, world.")
Hello, world.
>>> fun("test.", verbose=True)
Let me just say, test.
>>> fun(42, verbose=True)
Strength in numbers, eh? 42
>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
>>> fun(None)
Nothing.
>>> fun(1.23)
0.615

В случае отсутствия зарегистрированной реализации для определенного типа используется порядок разрешения методов для поиска более общей реализации. Исходная функция, декорированная @singledispatch, зарегистрирована для базового типа object, что означает, что она используется, если лучшая реализация не найдена.

Если реализация зарегистрирована для абстрактного базового класса, виртуальные подклассы базового класса будут обработаны с помощью этой реализации:

>>> from collections.abc import Mapping
>>> @fun.register
... def _(arg: Mapping, verbose=False):
...     if verbose:
...         print("Keys & Values")
...     for key, value in arg.items():
...         print(key, "=>", value)
...
>>> fun({"a": "b"})
a => b

Чтобы проверить, какую реализацию обобщенная функция выберет для данного типа, используйте атрибут dispatch():

>>> fun.dispatch(float)
<function fun_num at 0x1035a2840>
>>> fun.dispatch(dict)    # note: default implementation
<function fun at 0x103fe0000>

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

>>> fun.registry.keys()
dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>,
          <class 'decimal.Decimal'>, <class 'list'>,
          <class 'float'>])
>>> fun.registry[float]
<function fun_num at 0x1035a2840>
>>> fun.registry[object]
<function fun at 0x103fe0000>

Добавлена в версии 3.4.

Изменено в версии 3.7: Атрибут register() теперь поддерживает использование аннотаций типов.

Изменено в версии 3.11: Атрибут register() теперь поддерживает types.UnionType и typing.Union в качестве аннотаций типов.

class functools.singledispatchmethod(func)

Преобразует метод в функцию с однократным вызовом обобщенную функцию.

Для определения обобщенного метода используйте декоратор @singledispatchmethod. При определении функции с помощью @singledispatchmethod, обратите внимание, что диспетчеризация происходит по типу первого аргумента, отличного от self или cls:

class Negator:
    @singledispatchmethod
    def neg(self, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    def _(self, arg: int):
        return -arg

    @neg.register
    def _(self, arg: bool):
        return not arg

@singledispatchmethod поддерживает вложение с другими декораторами, такими как @classmethod. Обратите внимание, что для поддержки dispatcher.register, singledispatchmethod должен быть внешним декоратором. Вот класс Negator с методами neg привязанными к классу, а не к экземпляру класса:

class Negator:
    @singledispatchmethod
    @classmethod
    def neg(cls, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    @classmethod
    def _(cls, arg: int):
        return -arg

    @neg.register
    @classmethod
    def _(cls, arg: bool):
        return not arg

Такой же подход можно использовать для других похожих декораторов: @staticmethod, @abstractmethod и другие.

Добавлена в версии 3.8.

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

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

Для доступа к исходной функции с целью интроспекции и других целей (например, для обхода декораторов кеширования, таких как lru_cache()) эта функция автоматически добавляет атрибут __wrapped__ в функцию-обертку, который ссылается на обернутую функцию.

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

update_wrapper() может использоваться с вызываемыми объектами, отличными от функций. Любые атрибуты, указанные в assigned или updated, отсутствующие в объекте, который обертывается, игнорируются (т. е. эта функция не попытается установить их в функцию-обертку). AttributeError всё ещё генерируется, если у самой функции-обертки отсутствуют атрибуты, указанные в updated.

Изменено в версии 3.2: Атрибут __wrapped__ теперь автоматически добавляется. Атрибут __annotations__ теперь копируется по умолчанию. Отсутствующие атрибуты больше не вызывают AttributeError.

Изменено в версии 3.4: Атрибут __wrapped__ теперь всегда ссылается на обернутую функцию, даже если эта функция определяла атрибут __wrapped__. (см. bpo-17482)

Изменено в версии 3.12: Атрибут __type_params__ теперь копируется по умолчанию.

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

Это удобная функция для вызова update_wrapper() в качестве декоратора функции при определении оберточной функции. Она эквивалентна 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():
...     """Docstring"""
...     print('Called example function')
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'

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

Объекты partial

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

partial.func

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

partial.args

Позиционные аргументы, которые будут добавлены в начало позиционных аргументов, переданных в вызов объекта partial.

partial.keywords

Ключевые аргументы, которые будут переданы при вызове объекта partial.

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

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/functools.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API