functools
— Функции и операции высшего порядка над вызываемыми объектами¶
Исходный код: Lib/functools.py
Модуль functools
предназначен для функций более высокого порядка: функций,
которые действуют на или возвращает другие функции. Как правило, любой вызываемый
объект может рассматриваться как функция для целей данного модуля.
Модуль functools
определяет следующие функции:
-
@
functools.
cached_property
(func)¶ Преобразование метода класса в свойство, значение которого вычисляется один раз, а затем кэшируется как обычный атрибут для срока службы сущность. Аналогично
property()
, с добавлением кэширование. Полезен для дорогостоящих вычисляемых свойств сущности, которые в остальном являются эффективно неизменным.Пример:
class DataSet: def __init__(self, sequence_of_numbers): self._data = sequence_of_numbers @cached_property def stdev(self): return statistics.stdev(self._data) @cached_property def variance(self): return statistics.variance(self._data)
Добавлено в версии 3.8.
Примечание
Этот декоратор требует, чтобы
__dict__
атрибут на каждом сущность были изменяемым отображением (неизменный). Это означает, что он не будет работать с некоторыми типами, такими как metaclasses (поскольку__dict__
атрибуты типа сущности являются прокси только для чтения для пространства имен классов), и теми, которые задают__slots__
без включения__dict__
в качестве одного из определенных слотов (поскольку такие классы вообще не предоставляют__dict__
атрибут).
-
functools.
cmp_to_key
(func)¶ Преобразование функции сравнения старого стиля в ключевой функции. Используется с инструментами, принимающими ключевые функции (такие как
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
). Эта функция - прежде всего, используемый как инструмент перехода для программ, преобразовываемых из Python 2, который поддержал использование функций сравнения.Функция сравнения - это любая вызываемая функция, которая принимает два аргумента, сравнивает их и возвращает отрицательное число для меньше, ноль для равенства или положительное число для больше. Ключевая функция - подлежащее выкупу, которое принимает один аргумент и возвращает другой значение, чтобы быть используемый как ключом вида.
Пример:
sorted(iterable, key=cmp_to_key(locale.strcoll)) # порядок сортировки с учетом локали
Примеры сортировки и краткое учебное пособие по сортировке см. в разделе HOWTO по сортировке.
Добавлено в версии 3.2.
-
@
functools.
lru_cache
(user_function)¶ -
@
functools.
lru_cache
(maxsize=128, typed=False) Декоратор, чтобы обернуть функцию memoizing подлежащим выкупу, которое экономит до новых требований maxsize. Это может сэкономить время, когда дорогое или I/O связанная функция периодически называют с теми же аргументами.
Так как словарь - используемый к результатам кэш, позиционные и аргументы ключевой функции должны быть хэшируемым.
Отдельные шаблоны аргументов могут рассматриваться как отдельные вызовы с отдельными записями кэш. Например, f(a=1, b=2) and f(b=2, a=1) отличаются порядком ключевых аргументов и могут иметь две отдельные записи кэша.
Если задан параметр user_function, он должен быть вызываемым. Это позволяет декоратору lru_cache быть примененным непосредственно к пользовательской функции, оставляя maxsize в его дефолте значение 128:
@lru_cache def count_vowels(sentence): sentence = sentence.casefold() return sum(sentence.count(vowel) for vowel in 'aeiou')
Если maxsize установлен в
None
, опция LRU отключена, и кэш может вырасти без связанного.Если typed будет установлен в истинный, то аргументы функции различных типов припрячутся про запас отдельно. Например,
f(3)
иf(3.0)
будут рассматриваться как отдельные вызовы с различными результатами.Чтобы помочь измерить эффективность кэш и настроить параметр maxsize, обернутая функция инструментована с функцией
cache_info()
, которая возвращает именованный кортеж, показывающий hits, misses, maxsize и currsize. В многопоточной среде совпадения и промахи являются приблизительными.Декоратор также предоставляет функцию
cache_clear()
для очистки или аннулирования кэш.Исходная базовая функция доступна через
__wrapped__
атрибут. Это полезно для самоанализа, для обхода кэш или для переформатирования функции другим кэш.LRU (least recently used) cache работает лучше всего, когда самые последние звонки являются лучшими предикторами предстоящих вызовов (например, самые популярные статьи на сервере новостей имеют тенденцию меняться каждый день). Ограничение размера кэш гарантирует, что кэш не будет расти без привязки к длительным процессам, таким как веб-серверы.
В целом LRU кэш должен только быть используемый, когда вы хотите снова использовать ранее вычисленный значения. Соответственно, нет смысла кэш функции с побочными эффектами, функции, которые должны создавать различные изменяемые объекты на каждом вызове, или нечистые функции, такие как time () или random ().
Пример LRU кэш для статического веб-контента:
@lru_cache(maxsize=32) def get_pep(num): 'Получить текст предложения по улучшению Python' resource = 'http://www.python.org/dev/peps/pep-%04d/' % num 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.
-
@
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()))
Примечание
В то время как этот декоратор помогает создать полностью заказанные типы хорошего поведения, это, does прибывают за счет более медленного выполнения и более сложных трассировок стека для полученных методов сравнения. Если сравнительный анализ производительности показывает, что это узкое место для данного приложения, внедрение всех шести богатых методов сравнения, скорее всего, обеспечит простое повышение скорости.
Добавлено в версии 3.2.
Изменено в версии 3.4: Теперь поддерживается возврат NotImplemented из базовой функции сравнения для нераспознанных типов.
-
functools.
partial
(func, /, *args, **keywords)¶ Возвращает новая частичный объект, которая при вызове будет вести себя как 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
дескриптор возвращает a, который ведет себя какpartial
за исключением того, что он разработан, чтобы быть используемый как определением метода вместо того, чтобы быть непосредственно подлежащим выкупу.func должен быть дескриптором или вызываемым (объекты, которые оба, как и обычные функции, обрабатываются как дескрипторы).
Когда func - дескриптор (такой как нормальная функция Python,
classmethod()
,staticmethod()
,abstractmethod()
или другой сущностьpartialmethod
), требования к__get__
делегированы к основному дескриптор и соответствующему частичный объект возвращенный как результат.Когда func - non-дескриптор подлежащее выкупу, соответствующий связанный метод создан динамично. Это ведет себя как обычная функция Python, когда используемый как метод: аргумент self будет вставлен в качестве первого позиционного аргумента, даже перед args и keywords, предоставленными конструктору
partialmethod
.Пример:
>>> class Cell(object): ... 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[, initializer])¶ Применить function двух аргументов кумулятивно к элементам iterable слева направо, чтобы уменьшить итабль до одного значение. Например,
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
вычисляет((((1+2)+3)+4)+5)
. Левый аргумент, x, является накопленным значение, а правый аргумент, y, является обновлением значение из iterable. Если присутствует необязательная initializer, она помещается перед элементами итабля в вычислении и служит по умолчанию, когда итабль пуст. Если initializer не дан, и iterable содержит только один предмет, первый предмет возвращен.Примерно эквивалентный:
def reduce(function, iterable, initializer=None): it = iter(iterable) if initializer is None: value = next(it) else: value = initializer for element in it: value = function(value, element) return value
См. раздел
itertools.accumulate()
для итератора, который дает все промежуточные значения.
-
@
functools.
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)
Для код, которые не используют аннотации типа, соответствующий аргумент типа может быть передан явно самому декоратору:
>>> @fun.register(complex) ... def _(arg, verbose=False): ... if verbose: ... print("Better than complicated.", end=" ") ... print(arg.real, arg.imag) ...
Чтобы включить регистрацию лямбд и ранее существовавших функций,
register()
атрибут может быть используемый в функциональной форме:>>> def nothing(arg, verbose=False): ... print("Nothing.") ... >>> fun.register(type(None), nothing)
register()
атрибут возвращает декорированную функцию, которая включает декоратору, складывающему, пиклинг, а также создающему модульные тесты на каждый вариант независимо:>>> @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
, что означает, что она используемый, если лучшей реализации не найдено.Для проверки того, какую реализацию выберет родовая функция для данного типа, используйте функцию
dispatch()
атрибут:>>> fun.dispatch(float) <function fun_num at 0x1035a2840> >>> fun.dispatch(dict) # примечание: реализация по умолчанию <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()
атрибут, используя аннотации типа.
-
class
functools.
singledispatchmethod
(func)¶ Преобразование метода в одиночную диспетчеризацию универсальной функции.
Чтобы определить общий метод, декорируйте его декоратором
@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, чтобы она выглядела как функция wrapped. Необязательными аргументами являются кортежи, указывающие, какие атрибуты исходной функции назначаются непосредственно соответствующим атрибуты функции-оболочки, а какие атрибуты функции-оболочки обновляются соответствующими атрибуты из исходной функции. значения по умолчанию для этих аргументов - константы уровня модуля
WRAPPER_ASSIGNMENTS
(который назначает на__module__
функции обертки,__name__
,__qualname__
,__annotations__
и__doc__
, документацию строка), иWRAPPER_UPDATES
(который обновляет__dict__
функции обертки, т.е. словарь сущность).Чтобы предоставить доступ к оригинальной функции для самоанализа и других целей (например, обход декоратора кэширование, таких как
lru_cache()
), эта функция автоматически добавляет__wrapped__
атрибут к обертке, которая относится к обертываемой функции.Главное надлежащее использование для этой функции находится в функциях декоратор, которые обертывают декорированную функцию и возвращает обертку. Если функция-обертка не обновляется, метаданные возвращенный функции будут отражать определение обертки, а не исходное определение функции, которое обычно является менее полезным.
update_wrapper()
может быть используемый с вызываемыми объектами, отличными от функций. Все атрибуты, именованные в assigned или updated, отсутствующие в обертываемом объекте, игнорируются (т.е. эта функция не будет пытаться установить их в функции обертки).AttributeError
все еще возникает, если в самой функции-оболочке отсутствует какая-либо атрибуты, названная в updated.Добавлено в версии 3.2: Автоматическое добавление
__wrapped__
атрибут.Добавлено в версии 3.2: Копирование
__annotations__
атрибут по умолчанию.Изменено в версии 3.2: Отсутствующие атрибуты больше не запускают
AttributeError
.Изменено в версии 3.4: Теперь
__wrapped__
атрибут всегда ссылается на упакованную функцию, даже если эта функция определила__wrapped__
атрибут. (см. bpo-17482)
-
@
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
похожи на объекты function
в том, что они
являются вызываемыми, слабыми и могут иметь атрибуты. Есть некоторые важные
различия. Для сущность __name__
и __doc__
атрибуты
не создаются автоматически. Кроме того, объекты partial
, определенные в
классах, ведут себя как статические методы и не преобразуются в связанные методы
во время поиска сущность атрибут.