functools
— Funciones de orden superior y operaciones sobre objetos invocables¶
Código fuente: Lib/functools.py
El módulo functools
es para funciones de orden superior: funciones que actúan o retornan otras funciones. En general, cualquier objeto invocable puede ser tratado como una función para los propósitos de este módulo.
El módulo functools
define las siguientes funciones:
-
@
functools.
cache
(user_function)¶ Caché de funciones ilimitado, ligero y simple. Aveces llamado «memoización».
Retorna lo mismo que
lru_cache(maxsize=None)
, creando una envoltura delgada alrededor de una búsqueda de diccionario para los argumentos de la función. Debido a que nunca necesita desalojar los valores antiguos, esto es más pequeño y más rápido quelru_cache()
con un límite de tamaño.Por ejemplo:
@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
Nuevo en la versión 3.9.
-
@
functools.
cached_property
(func)¶ Transforma un método de una clase en una propiedad cuyo valor se computa una vez y luego se almacena como un atributo normal durante la vida de la instancia. Similar a
property()
, con la adición de caching. Útil para propiedades calculadas costosas de instancias que de otra manera son efectivamente inmutables.Ejemplo:
class DataSet: def __init__(self, sequence_of_numbers): self._data = tuple(sequence_of_numbers) @cached_property def stdev(self): return statistics.stdev(self._data)
La mecánica de
cached_property()
es algo diferente deproperty()
. Un atributo de bloques de propiedad normal escribe a menos que se defina un establecedor. Por el contrario, cached_property permite escrituras.El decorador cached_property solo se ejecuta en búsquedas y solo cuando no existe un atributo con el mismo nombre. Cuando se ejecuta, cached_property escribe en el atributo con el mismo nombre. Las lecturas y escrituras de atributos posteriores tienen prioridad sobre el método cached_property y funciona como un atributo normal.
El valor en caché se puede borrar eliminando el atributo. Esto permite que el método cached_property se ejecute nuevamente.
Tenga en cuenta que este decorador interfiere con el funcionamiento de diccionarios de intercambio de claves PEP 412. Esto significa que los diccionarios de instancias pueden ocupar más espacio de lo habitual.
Además, este decorador requiere que el atributo
__dict__
en cada instancia sea un mapeo mutable. Esto significa que no funcionará con algunos tipos, como las metaclases (ya que los atributos__dict__
en las instancias de tipos son proxies de solo lectura para el espacio de nombres de la clase) y aquellos que especifican__slots__
sin incluir__dict__
como una de las ranuras definidas (ya que tales clases no proporcionan un atributo__dict__
en absoluto).Si un mapeo mutable no está disponible o si se desea compartir claves con espacio eficiente, se puede lograr un efecto similar a
cached_property()
apilandoproperty()
encima decache()
:class DataSet: def __init__(self, sequence_of_numbers): self._data = sequence_of_numbers @property @cache def stdev(self): return statistics.stdev(self._data)
Nuevo en la versión 3.8.
-
functools.
cmp_to_key
(func)¶ Transformar una función de comparación de estilo antiguo en una key function. Se utiliza con herramientas que aceptan funciones clave (como
sorted()
,min()
,max()
,heapq.nlargest()
,heapq.nsmallest()
,itertools.groupby()
). Esta función se utiliza principalmente como una herramienta de transición para los programas que se están convirtiendo a partir de Python 2, que soportaba el uso de funciones de comparación.A comparison function is any callable that accepts two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one argument and returns another value to be used as the sort key.
Ejemplo:
sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order
Para ejemplos de clasificación y un breve tutorial de clasificación, ver HOW TO - Ordenar.
Nuevo en la versión 3.2.
-
@
functools.
lru_cache
(user_function)¶ -
@
functools.
lru_cache
(maxsize=128, typed=False) Decorador para envolver una función con un memorizador invocable que guarda hasta el maxsize de las llamadas más recientes. Puede salvar el tiempo cuando una función costosa o de E/S es llamada periódicamente con los mismos argumentos.
Since a dictionary is used to cache results, the positional and keyword arguments to the function must be hashable.
Los patrones de argumento distintos pueden considerarse como llamadas distintas con entradas de caché separadas. Por ejemplo, f(a=1, b=2) y f(b=2, a=1) difieren en el orden de los argumentos de las palabras clave y pueden tener dos entradas de caché separadas.
Si se especifica user_function, debe ser una llamada. Esto permite que el decorador lru_cache se aplique directamente a una función de usuario, dejando el maxsize en su valor por defecto de 128:
@lru_cache def count_vowels(sentence): return sum(sentence.count(vowel) for vowel in 'AEIOUaeiou')
Si maxsize está configurado como
None
, la función LRU está desactivada y la caché puede crecer sin límites.If typed is set to true, function arguments of different types will be cached separately. If typed is false, the implementation will usually regard them as equivalent calls and only cache a single result. (Some types such as str and int may be cached separately even when typed is false.)
Note, type specificity applies only to the function’s immediate arguments rather than their contents. The scalar arguments,
Decimal(42)
andFraction(42)
are be treated as distinct calls with distinct results. In contrast, the tuple arguments('answer', Decimal(42))
and('answer', Fraction(42))
are treated as equivalent.La función envuelta está instrumentada con una función
cache_parameters()
que retorna un nuevodict
que muestra los valores para maxsize y typed. Esto es solo para fines informativos. La mutación de los valores no tiene ningún efecto.Para ayudar a medir la efectividad de la caché y afinar el parámetro maxsize, la función envolvente está instrumentada con una función
cache_info()
que retorna un named tuple mostrando hits, misses, maxsize y currsize.El decorador también proporciona una función
cache_clear()
para limpiar o invalidar la caché.La función subyacente original es accesible a través del atributo
__wrapped__
. Esto es útil para la introspección, para evitar el caché, o para volver a envolver la función con un caché diferente.La caché mantiene referencias de los argumentos y retorna los valores hasta que se caduquen de la caché o hasta que se borre la caché.
Un caché LRU (menos usado recientemente) funciona mejor cuando las llamadas más recientes son los mejores predictores de las próximas llamadas (por ejemplo, el los artículos más populares en un servidor de noticias tienden a cambiar cada día). El límite de tamaño de la caché asegura que la caché no crezca sin límites en procesos de larga ejecución como servidores web.
En general, la caché de la LRU sólo debe utilizarse cuando se desea reutilizar valores previamente calculados. Por consiguiente, no tiene sentido almacenar en la caché funciones con efectos secundarios, funciones que necesitan crear distintos objetos mutables en cada llamada, o funciones impuras como time() o random().
Ejemplo de un caché de la LRU para contenido web estático:
@lru_cache(maxsize=32) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = 'https://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)
Ejemplo de computar eficientemente los «números de Fibonacci» <https://en.wikipedia.org/wiki/Fibonacci_number>`_ usando una memoria caché para implementar una «programación dinámica» <https://en.wikipedia.org/wiki/Dynamic_programming>`_ técnica:
@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)
Nuevo en la versión 3.2.
Distinto en la versión 3.3: Añadida la opción typed option.
Distinto en la versión 3.8: Añadida la opción user_function.
Nuevo en la versión 3.9: Añadida la función
cache_parameters()
-
@
functools.
total_ordering
¶ Dada una clase que define uno o más métodos de ordenamiento de comparación ricos, este decorador de clase suministra el resto. Esto simplifica el esfuerzo de especificar todas las posibles operaciones de comparación rica:
La clase debe definir uno de
__lt__()
,__le__()
,__gt__()
, o__ge__()
. Además, la clase debe suministrar un método__eq__()
. Dada una clase que define uno o más métodos de ordenamiento de comparación ricos, este decorador de clase suministra el resto. Esto simplifica el esfuerzo de especificar todas las posibles operaciones de comparación rica.Por ejemplo:
@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()))
Nota
Mientras que este decorador facilita la creación de tipos bien comportados y totalmente ordenados, does a costa de una ejecución más lenta y de trazos de pila (stack traces) más complejos para los métodos de comparación derivados. Si la evaluación comparativa del rendimiento indica que se trata de un cuello de botella para una aplicación determinada, la aplicación de los seis métodos de comparación ricos en su lugar es probable que proporcione un fácil aumento de la velocidad.
Nota
Este decorador no intenta anular métodos que han sido declarados en la clase sus superclases. Lo que significa que si una superclase define un operador de comparación, total_ordering no lo implementará de nuevo, incluso si el método original es abstracto.
Nuevo en la versión 3.2.
Distinto en la versión 3.4: Retornando NotImplemented de la función de comparación subyacente para los tipos no reconocidos está ahora soportado.
-
functools.
partial
(func, /, *args, **keywords)¶ Retorna un nuevo partial object que cuando sea llamado se comportará como func llamado con los argumentos posicionales args y los argumentos de palabras clave keywords. Si se suministran más argumentos a la llamada, se añaden a args. Si se suministran más argumentos de palabras clave, se extienden y anulan las keywords. Aproximadamente equivalente a:
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
El
partial()
se utiliza para la aplicación de funciones parciales que «congela» (freezes) alguna porción de los argumentos y/o palabras clave de una función dando como resultado un nuevo objeto con una firma simplificada. Por ejemplo,partial()
puede usarse para crear una llamada que se comporte como la funciónint()
donde el argumento base tiene un valor por defecto de dos:>>> 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)¶ Retorna un nuevo descriptor
partialmethod
que se comporta comopartial
excepto que está diseñado para ser usado como una definición de método en lugar de ser directamente invocable.func debe ser un descriptor o un invocable (los objetos que son ambos, como las funciones normales, se manejan como descriptores).
Cuando func es un descriptor (como una función Python normal,
classmethod()
,staticmethod()
,abstractmethod()
u otra instancia departialmethod
), las llamadas a__get__
se delegan al descriptor subyacente, y se retorna un partial object apropiado como resultado.Cuando func es una llamada no descriptiva, se crea dinámicamente un método de unión apropiado. Esto se comporta como una función Python normal cuando se usa como método: el argumento self se insertará como el primer argumento posicional, incluso antes de las args y keywords suministradas al constructor
partialmethod
.Ejemplo:
>>> 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
Nuevo en la versión 3.4.
-
functools.
reduce
(function, iterable[, initializer])¶ Aplicar una función de dos argumentos acumulativos a los elementos de iterable, de izquierda a derecha, para reducir los itables a un solo valor. Por ejemplo,
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
calcula((((1+2)+3)+4)+5)
. El argumento de la izquierda, x, es el valor acumulado y el de la derecha, y, es el valor de actualización del iterable. Si el initializer opcional está presente, se coloca antes de los ítems de la iterable en el cálculo, y sirve como predeterminado cuando la iterable está vacía. Si no se da el initializer y el iterable contiene sólo un elemento, se retorna el primer elemento.Aproximadamente equivalente a:
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
Ver
itertools.accumulate()
para un iterador que produce todos los valores intermedios.
-
@
functools.
singledispatch
¶ Transformar una función en una single-dispatch generic function.
To define a generic function, decorate it with the
@singledispatch
decorator. When defining a function using@singledispatch
, note that the dispatch happens on the type of the first argument:>>> from functools import singledispatch >>> @singledispatch ... def fun(arg, verbose=False): ... if verbose: ... print("Let me just say,", end=" ") ... print(arg)
To add overloaded implementations to the function, use the
register()
attribute of the generic function, which can be used as a decorator. For functions annotated with types, the decorator will infer the type of the first argument automatically:>>> @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)
Para el código que no utiliza anotaciones de tipo, el argumento de tipo apropiado puede ser pasado explícitamente al propio decorador:
>>> @fun.register(complex) ... def _(arg, verbose=False): ... if verbose: ... print("Better than complicated.", end=" ") ... print(arg.real, arg.imag) ...
To enable registering lambdas and pre-existing functions, the
register()
attribute can also be used in a functional form:>>> def nothing(arg, verbose=False): ... print("Nothing.") ... >>> fun.register(type(None), nothing)
The
register()
attribute returns the undecorated function. This enables decorator stacking,pickling
, and the creation of unit tests for each variant independently:>>> @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
Cuando se llama, la función genérica despacha sobre el tipo del primer argumento:
>>> 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
Where there is no registered implementation for a specific type, its method resolution order is used to find a more generic implementation. The original function decorated with
@singledispatch
is registered for the baseobject
type, which means it is used if no better implementation is found.If an implementation is registered to an abstract base class, virtual subclasses of the base class will be dispatched to that implementation:
>>> 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
To check which implementation the generic function will choose for a given type, use the
dispatch()
attribute:>>> fun.dispatch(float) <function fun_num at 0x1035a2840> >>> fun.dispatch(dict) # note: default implementation <function fun at 0x103fe0000>
Para acceder a todas las implementaciones registradas, utilice el atributo
registry
de sólo lectura:>>> 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>
Nuevo en la versión 3.4.
Distinto en la versión 3.7: The
register()
attribute now supports using type annotations.
-
class
functools.
singledispatchmethod
(func)¶ Transformar un método en un single-dispatch generic function.
To define a generic method, decorate it with the
@singledispatchmethod
decorator. When defining a function using@singledispatchmethod
, note that the dispatch happens on the type of the first non-self or non-cls argument: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
supports nesting with other decorators such as@classmethod
. Note that to allow fordispatcher.register
,singledispatchmethod
must be the outer most decorator. Here is theNegator
class with theneg
methods bound to the class, rather than an instance of the class: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
The same pattern can be used for other similar decorators:
@staticmethod
,@abstractmethod
, and others.Nuevo en la versión 3.8.
-
functools.
update_wrapper
(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)¶ Actualiza una función wrapper para que se parezca a la función wrapped. Los argumentos opcionales son tuplas para especificar qué atributos de la función original se asignan directamente a los atributos coincidentes en la función contenedora y qué atributos de la función contenedora se actualizan con los atributos correspondientes de la función original. Los valores predeterminados para estos argumentos son las constantes de nivel de módulo
WRAPPER_ASSIGNMENTS
(que se asigna a la función contenedora__module__
,__name__
,__qualname__
,__annotations__
y__doc__
, la cadena de caracteres de documentación) yWRAPPER_UPDATES
(que actualiza el__dict__
de la función contenedora, es decir, el diccionario de instancia).Para permitir el acceso a la función original para la introspección y otros propósitos (por ejemplo, evitando un decorador de caché como
lru_cache()
), esta función añade automáticamente un atributo__wrapped__
al envoltorio que se refiere a la función que se está envolviendo.El principal uso previsto para esta función es en decorator functions que envuelven la función decorada y retornan el envoltorio. Si la función de envoltura no se actualiza, los metadatos de la función retornada reflejarán la definición de la envoltura en lugar de la definición de la función original, lo que normalmente no es de gran ayuda.
update_wrapper()
puede ser usado con otros invocables que no sean funciones. Cualquier atributo nombrado en assigned o updated que falte en el objeto que se está invoca se ignora (es decir, esta función no intentará establecerlos en la función de envoltura (wrapper)).AttributeError
sigue apareciendo si la propia función de envoltura no tiene ningún atributo nombrado en updated.Nuevo en la versión 3.2: Adición automática de
__wrapped__
attribute.Nuevo en la versión 3.2: Copia del atributo
__annotations__
por defecto.Distinto en la versión 3.2: Los atributos faltantes ya no desencadenan un
AtributoError
.Distinto en la versión 3.4: El atributo
__wrapped__
ahora siempre se refiere a la función envuelta, incluso si esa función definió un atributo__wrapped__
. (see :issue:17482
)
-
@
functools.
wraps
(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)¶ Esta es una función conveniente para invocar
update_wrapper()
como decorador de la función cuando se define una función de envoltura (wrapper). Es equivalente apartial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)
. Por ejemplo:>>> 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'
Sin el uso de esta fábrica de decoradores, el nombre de la función de ejemplo habría sido
'wrapper'
, y el docstring de laexample()
se habría perdido.
partial
Objetos¶
Los objetos partial
son objetos invocables creados por partial()
. Tienen tres atributos de sólo lectura:
-
partial.
func
¶ Un objeto o función invocable. Las llamadas al objeto
partial
serán reenviadas afunc
con nuevos argumentos y palabras clave.
-
partial.
args
¶ Los argumentos posicionales de la izquierda que se prepararán para los argumentos posicionales proporcionados un llamado al objeto
partial
.
-
partial.
keywords
¶ Los argumentos de la palabra clave que se suministrarán cuando se llame al objeto
partial
.
Los objetos partial
son como los objetos function
que son invocables, de referencia débil y pueden tener atributos. Hay algunas diferencias importantes. Por ejemplo, los atributos __name__
y __doc__
no se crean automáticamente. Además, los objetos partial
definidos en las clases se comportan como métodos estáticos y no se transforman en métodos vinculados durante la búsqueda de atributos de la instancia.