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.

@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 (вытеснение давно не использовавшихся элементов) лучше всего работает, когда последние вызовы позволяют наиболее точно предсказать будущие (например, самые популярные статьи на новостном сервере обычно меняются каждый день). Ограничение размера кэша гарантирует, что в долго работающих процессах, таких как веб-серверы, размер кэша не будет расти без ограничений.

В целом кэш 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, ]/)

Применяет двухаргументную function к элементам iterable последовательно, слева направо, сводя итерируемый объект к одному значению. Например, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) вычисляет ((((1+2)+3)+4)+5). Левый аргумент, x, — это накопленное значение, а правый аргумент, y, — обновляемое значение из iterable. Если задан необязательный параметр 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, @~abc.abstractmethod и другими.

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

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

Обновляет функцию-wrapper, чтобы она выглядела как обёрнутая функция wrapped. Необязательные аргументы — это кортежи, задающие, какие атрибуты исходной функции напрямую присваиваются соответствующим атрибутам функции-обёртки и какие атрибуты функции-обёртки обновляются соответствующими атрибутами исходной функции. Значениями по умолчанию для этих аргументов являются константы уровня модуля 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__ теперь копируется по умолчанию.

@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–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/functools.html

Spec-Zone.ru

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