functools — Funktioner av högre ordning och operationer på anropsbara objekt

Källkod: Lib/functools.py


Modulen functools är avsedd för funktioner av högre ordning: funktioner som agerar på eller returnerar andra funktioner. I allmänhet kan alla anropsbara objekt behandlas som en funktion i den här modulen.

Modulen functools definierar följande funktioner:

@functools.cache(user_function)

Enkel lättviktig obegränsad funktionscache. Kallas ibland för ”memoize”.

Returnerar samma sak som lru_cache(maxsize=None), vilket skapar ett tunt hölje runt en ordboksuppslagning för funktionsargumenten. Eftersom den aldrig behöver evakuera gamla värden är den här mindre och snabbare än lru_cache() med en storleksbegränsning.

Till exempel:

@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

Cachen är trådsäker så att den omslutna funktionen kan användas i flera trådar. Detta innebär att den underliggande datastrukturen förblir sammanhängande under samtidiga uppdateringar.

Det är möjligt att den inkapslade funktionen anropas mer än en gång om en annan tråd gör ett ytterligare anrop innan det första anropet har slutförts och cachats.

Tillagd i version 3.9.

@functools.cached_property(func)

Omvandlar en metod i en klass till en egenskap vars värde beräknas en gång och sedan cachelagras som ett normalt attribut under instansens livstid. Liknar property(), med tillägg av cachelagring. Användbar för dyra beräknade egenskaper hos instanser som annars är effektivt oföränderliga.

Exempel:

klass DataSet:

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

    @cachad_egenskap
    def stdev(self):
        return statistik.stdev(self._data)

Mekaniken i cached_property() är något annorlunda än i property(). En vanlig property blockerar skrivningar av attribut om inte en setter är definierad. Däremot tillåter en cached_property skrivningar.

Dekoratorn cached_property körs endast vid uppslagningar och endast när ett attribut med samma namn inte existerar. När den körs skriver cached_property till attributet med samma namn. Efterföljande läsningar och skrivningar av attribut har företräde framför metoden cached_property och den fungerar som ett vanligt attribut.

Det cachade värdet kan rensas genom att attributet tas bort. Detta gör att metoden cached_property kan köras igen.

Egenskapen cached_property förhindrar inte ett möjligt tävlingsförhållande vid användning med flera trådar. Getter-funktionen kan köras mer än en gång på samma instans, där den senaste körningen ställer in det cachade värdet. Om den cachade egenskapen är idempotent eller på annat sätt inte skadlig för att köras mer än en gång på en instans, är detta bra. Om synkronisering behövs, implementera den nödvändiga låsningen i den dekorerade getter-funktionen eller runt åtkomsten till den cachade egenskapen.

Observera att denna dekorator stör funktionen hos PEP 412 nyckeldelningsordböcker. Detta innebär att instansordböcker kan ta mer utrymme än vanligt.

Den här dekoratorn kräver också att attributet __dict__ på varje instans är en muterbar mappning. Detta innebär att den inte kommer att fungera med vissa typer, till exempel metaklasser (eftersom attributen __dict__ på typinstanser är skrivskyddade proxyer för klassens namnrymd) och de som anger __slots__ utan att inkludera __dict__ som en av de definierade slottarna (eftersom sådana klasser inte tillhandahåller ett attribut __dict__ alls).

Om en mutabel mappning inte är tillgänglig eller om utrymmeseffektiv nyckeldelning önskas, kan en effekt som liknar cached_property() också uppnås genom att stapla property() ovanpå lru_cache(). Se Hur cachar jag metodanrop? för mer information om hur detta skiljer sig från cached_property().

Tillagd i version 3.8.

Ändrad i version 3.12: Före Python 3.12 inkluderade cached_property ett odokumenterat lås för att säkerställa att getter-funktionen garanterat bara kördes en gång per instans vid flertrådig användning. Låset var dock per egenskap, inte per instans, vilket kunde resultera i oacceptabelt hög låskonflikt. I Python 3.12+ är denna låsning borttagen.

functools.cmp_to_key(func)

Omvandlar en gammaldags jämförelsefunktion till en key function. Används med verktyg som accepterar nyckelfunktioner (t.ex. sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()). Denna funktion används främst som ett övergångsverktyg för program som konverteras från Python 2 som stödde användningen av jämförelsefunktioner.

En jämförelsefunktion är en anropsbar funktion som tar emot två argument, jämför dem och returnerar ett negativt tal för mindre än, noll för likhet eller ett positivt tal för större än. En nyckelfunktion är en anropsbar funktion som tar emot ett argument och returnerar ett annat värde som används som sorteringsnyckel.

Exempel:

sorterad(iterabel, nyckel=cmp_till_nyckel(locale.strcoll))  # lokalmedveten sorteringsordning

För sorteringsexempel och en kort sorteringshandledning, se Sorteringstekniker.

Tillagd i version 3.2.

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

Dekorator för att omsluta en funktion med en memoizing callable som sparar upp till maxsize senaste anrop. Det kan spara tid när en dyr eller I/O-bunden funktion anropas med jämna mellanrum med samma argument.

Cachen är trådsäker så att den omslutna funktionen kan användas i flera trådar. Detta innebär att den underliggande datastrukturen förblir sammanhängande under samtidiga uppdateringar.

Det är möjligt att den inkapslade funktionen anropas mer än en gång om en annan tråd gör ett ytterligare anrop innan det första anropet har slutförts och cachats.

Eftersom en ordbok används för att cacha resultat måste positionella argument och nyckelordsargument till funktionen vara hashable.

Olika argumentmönster kan betraktas som olika anrop med olika cacheposter. Till exempel skiljer sig f(a=1, b=2) och f(b=2, a=1) åt i ordningsföljden på nyckelordets argument och kan ha två separata cacheposter.

Om user_function specificeras måste den vara en callable. Detta gör att lru_cache-dekoratorn kan tillämpas direkt på en användarfunktion, och maxsize behåller sitt standardvärde på 128:

@lru_cache
def count_vowels(mening):
    return sum(mening.count(vokal) för vokal i 'AEIOUaeiou')

Om maxsize är satt till None inaktiveras LRU-funktionen och cacheminnet kan växa obegränsat.

Om typed är satt till true kommer funktionsargument av olika typer att cachas separat. Om typed är false kommer implementationen vanligtvis att betrakta dem som likvärdiga anrop och bara cacha ett enda resultat. (Vissa typer som str och int kan cachelagras separat även när typed är false.)

Observera att typspecificitet endast gäller funktionens omedelbara argument och inte deras innehåll. De skalära argumenten Decimal(42)) och Fraction(42)) behandlas som distinkta anrop med distinkta resultat. Däremot behandlas tupelargumenten ('answer', Decimal(42)) och ('answer', Fraction(42)) som likvärdiga.

Den omslutna funktionen är utrustad med en cache_parameters()-funktion som returnerar en ny dict som visar värdena för maxsize och typed. Detta är endast för informationsändamål. Mutation av värdena har ingen effekt.

För att hjälpa till att mäta effektiviteten i cacheminnet och justera parametern maxsize har den omslutna funktionen försetts med en cache_info()-funktion som returnerar en named tuple med hits, misses, maxsize och currsize.

Dekoratorn innehåller också en cache_clear()-funktion för att tömma eller inaktivera cachen.

Den underliggande originalfunktionen är tillgänglig via attributet __wrapped__. Detta är användbart för introspektion, för att kringgå cacheminnet eller för att återpacka funktionen med ett annat cacheminne.

Cachen behåller referenser till argumenten och returvärdena tills de åldras ut ur cachen eller tills cachen rensas.

Om en metod cachelagras inkluderas instansargumentet self i cacheminnet. Se Hur cachar jag metodanrop?

En LRU-cache (least recently used) fungerar bäst när de senaste anropen är de bästa indikatorerna på kommande anrop (t.ex. de mest populära artiklarna på en nyhetsserver tenderar att ändras varje dag). Cachens storleksbegränsning säkerställer att cacheminnet inte växer obegränsat i långvariga processer, t.ex. webbservrar.

I allmänhet bör LRU-cachen endast användas när du vill återanvända tidigare beräknade värden. Följaktligen är det inte meningsfullt att cachelagra funktioner med bieffekter, funktioner som måste skapa distinkta föränderliga objekt vid varje anrop (t.ex. generatorer och asynkrona funktioner) eller orena funktioner som time() eller random().

Exempel på en LRU-cache för statiskt webbinnehåll:

@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)

Exempel på effektiv beräkning av Fibonacci-tal med hjälp av en cache för att implementera en teknik för dynamisk programmering:

@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)

Tillagd i version 3.2.

Ändrad i version 3.3: Alternativet typed har lagts till.

Ändrad i version 3.8: Lagt till alternativet user_function.

Ändrad i version 3.9: Lagt till funktionen cache_parameters()

@functools.total_ordering

Om en klass definierar en eller flera ordningsmetoder för rik jämförelse, tillhandahåller denna klassdekorator resten. Detta förenklar arbetet med att specificera alla möjliga operationer för rik jämförelse:

Klassen måste definiera en av __lt__(), __le__(), __gt__() eller __ge__(). Dessutom bör klassen tillhandahålla en __eq__()-metod.

Till exempel:

@total_beställning
klass Student:
    def _is_valid_operand(self, other):
        return (hasattr(other, "efternamn") och
                hasattr(annan, "förnamn"))
    def __eq__(self, annan):
        if not self._is_valid_operand(other):
            return Ej implementerad
        return ((self.efternamn.lower(), self.förnamn.lower()) == (other.efternamn.lower())
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, annan):
        if not self._is_valid_operand(other):
            return Ej implementerad
        return ((self.efternamn.lower(), self.förnamn.lower()) <
                (other.efternamn.lower(), other.förnamn.lower())))

Anteckning

Den här dekoratorn gör det enkelt att skapa välfungerande, helt ordnade typer, men det sker på bekostnad av långsammare exekvering och mer komplexa stackspår för de härledda jämförelsemetoderna. Om prestandajämförelser visar att detta är en flaskhals för en viss applikation, är det troligt att det är enkelt att öka hastigheten genom att implementera alla sex rika jämförelsemetoderna istället.

Anteckning

Denna dekorator gör inga försök att åsidosätta metoder som har deklarerats i klassen eller dess superklasser. Det betyder att om en superklass definierar en jämförelseoperator, kommer total_ordering inte att implementera den igen, även om den ursprungliga metoden är abstrakt.

Tillagd i version 3.2.

Ändrad i version 3.4: Det finns nu stöd för att returnera NotImplemented från den underliggande jämförelsefunktionen för okända typer.

functools.Placeholder

Ett singleton-objekt som används som en sentinel för att reservera en plats för positionella argument vid anrop av partial() och partialmethod().

Tillagd i version 3.14.

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

Returnerar ett nytt partial object som när det anropas kommer att bete sig som func anropat med de positionella argumenten args och nyckelordsargumenten keywords. Om fler argument anges vid anropet läggs de till args. Om ytterligare nyckelordsargument anges utökar och åsidosätter de keywords. Ungefär likvärdig med:

def partial(func, /, *args, **nyckelord):
    def newfunc(*fler_args, **fler_nyckelord):
        return func(*args, *mer_args, **(nyckelord | mer_nyckelord))
    newfunc.func = func
    newfunc.args = args
    newfunc.nyckelord = nyckelord
    returnera newfunc

Funktionen partial() används för partiell funktionstillämpning som ”fryser” en del av en funktions argument och/eller nyckelord, vilket resulterar i ett nytt objekt med en förenklad signatur. Till exempel kan partial() användas för att skapa en anropsbar funktion som beter sig som int()-funktionen där base-argumentet som standard är 2:

>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18

Om Placeholder sentinels finns i args, kommer de att fyllas först när partial() anropas. Detta gör det möjligt att förfylla vilket positionsargument som helst med ett anrop till partial(); utan Placeholder kan endast det valda antalet ledande positionsargument förfyllas.

Om det finns några Placeholder sentineller måste alla fyllas vid anropstillfället:

>>> say_to_world = partial(print, Placeholder, Placeholder, "world!")
>>> say_to_world('Hello', 'dear')
Hello dear world!

Anropet av say_to_world('Hello') ger upphov till ett TypeError, eftersom endast ett positionellt argument anges, men det finns två platshållare som måste fyllas i.

Om partial() tillämpas på ett befintligt partial()-objekt, fylls Placeholder sentinels i input-objektet med nya positionsargument. En platshållare kan behållas genom att infoga en ny Placeholder sentinel till den plats som innehas av en tidigare Placeholder:

>>> from functools import partial, Placeholder as _
>>> remove = partial(str.replace, _, _, '')
>>> message = 'Hello, dear dear world!'
>>> remove(message, ' dear')
'Hello, world!'
>>> remove_dear = partial(remove, _, ' dear')
>>> remove_dear(message)
'Hello, world!'
>>> remove_first_dear = partial(remove_dear, _, 1)
>>> remove_first_dear(message)
'Hello, dear world!'

Placeholder kan inte skickas till partial() som ett nyckelordsargument.

Ändrad i version 3.14: Lagt till stöd för Placeholder i positionella argument.

class functools.partialmethod(func, /, *args, **keywords)

Returnerar en ny partialmethod deskriptor som beter sig som partial förutom att den är utformad för att användas som en metoddefinition snarare än att vara direkt anropsbar.

func måste vara en descriptor eller en callable (objekt som är både och, som vanliga funktioner, hanteras som descriptors).

När func är en deskriptor (t.ex. en vanlig Python-funktion, classmethod(), staticmethod(), abstractmethod() eller en annan instans av partialmethod), delegeras anrop till __get__ till den underliggande deskriptorn och ett lämpligt partialobjekt returneras som resultat.

När func är en non-descriptor callable, skapas en lämplig bunden metod dynamiskt. Detta beter sig som en vanlig Python-funktion när den används som en metod: argumentet self kommer att infogas som det första positionella argumentet, till och med före de args och keywords som anges i partialmethod-konstruktören.

Exempel:

>>> 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

Tillagd i version 3.4.

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

Tillämpa funktion med två argument kumulativt på objekten i iterabel, från vänster till höger, så att iterabeln reduceras till ett enda värde. Till exempel beräknar reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) ((((1+2)+3)+4)+5). Det vänstra argumentet, x, är det ackumulerade värdet och det högra argumentet, y, är uppdateringsvärdet från iterable. Om det valfria initial finns med placeras det före iterabelns objekt i beräkningen och fungerar som standard när iterabeln är tom. Om initial inte anges och iterable bara innehåller ett objekt, returneras det första objektet.

Ungefär motsvarande:

initial_missing = objekt()

def reduce(function, iterable, /, initial=initial_missing):
    det = iter(iterabel)
    om initial är initial_missing:
        värde = nästa(det)
    i annat fall
        värde = initial
    för element i it:
        värde = funktion(värde, element)
    returnerar värde

Se itertools.accumulate() för en iterator som ger alla mellanliggande värden.

Ändrad i version 3.14: initial stöds nu som ett nyckelordsargument.

@functools.singledispatch

Omvandla en funktion till en single-dispatch generisk funktion.

För att definiera en generisk funktion, dekorera den med dekoratorn @singledispatch. När du definierar en funktion med hjälp av @singledispatch, observera att dispatch sker på typen av det första argumentet:

>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
...     if verbose:
...         print("Let me just say,", end=" ")
...     print(arg)

För att lägga till överladdade implementationer till funktionen, använd register()-attributet för den generiska funktionen, som kan användas som en dekorator. För funktioner som är annoterade med typer kommer dekoratorn automatiskt att härleda typen av det första argumentet:

>>> @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)

typing.Union kan också användas:

>>> @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)
...

För kod som inte använder typannoteringar kan det lämpliga typargumentet skickas explicit till själva dekoratorn:

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

För kod som skickar på en samlingstyp (t.ex. list), men som vill typmarkera objekten i samlingen (t.ex. list[int]), bör sändningstypen skickas uttryckligen till dekoratorn själv med typmarkeringen som går in i funktionsdefinitionen:

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

Anteckning

Vid körning kommer funktionen att skickas till en instans av en lista oavsett vilken typ som finns i listan, dvs. [1,2,3] kommer att skickas på samma sätt som ["foo", "bar", "baz"]. Annoteringen i det här exemplet är endast avsedd för statiska typkontrollanter och har ingen inverkan på körtiden.

För att möjliggöra registrering av lambdas och redan existerande funktioner kan attributet register() också användas i en funktionell form:

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

Attributet register() returnerar den odekorerade funktionen. Detta möjliggör stapling av dekoratorer, pickling, och skapandet av enhetstester för varje variant oberoende av varandra:

>>> @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

När den generiska funktionen anropas dispatchas den utifrån typen av det första argumentet:

>>> 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

Om det inte finns någon registrerad implementation för en viss typ används dess metodupplösningsordning för att hitta en mer generisk implementation. Den ursprungliga funktionen dekorerad med @singledispatch är registrerad för bastypen object, vilket innebär att den används om ingen bättre implementation hittas.

Om en implementation är registrerad för en abstrakt basklass, kommer virtuella subklasser av basklassen att skickas till denna 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

För att kontrollera vilken implementering den generiska funktionen kommer att välja för en viss typ, använd attributet dispatch():

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

För att få tillgång till alla registrerade implementationer, använd det skrivskyddade attributet 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>

Tillagd i version 3.4.

Ändrad i version 3.7: Attributet register() stöder nu användning av typannoteringar.

Ändrad i version 3.11: Attributet register() stöder nu typing.Union som typannotering.

class functools.singledispatchmethod(func)

Omvandla en metod till en single-dispatch generic function.

För att definiera en generisk metod, dekorera den med dekoratorn @singledispatchmethod. När du definierar en funktion med hjälp av @singledispatchmethod, observera att dispatch sker på typen av det första argumentet som inte är self eller cls:

klass Negator:
    @singledispatchmetod
    def neg(self, arg):
        raise NotImplementedError("Kan inte negera a")

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

    @neg.register
    def _(self, arg: bool):
        returnerar inte arg

@singledispatchmethod stöder nestning med andra dekoratorer som @classmethod. Notera att för att tillåta dispatcher.register måste singledispatchmethod vara den yttersta dekoratorn. Här är Negator klassen med neg metoderna bundna till klassen, snarare än en instans av klassen:

klass Negator:
    @singledispatchmetod
    @klassmetod
    def neg(cls, arg):
        raise NotImplementedError("Kan inte negera a")

    @neg.register
    @klassmetod
    def _(cls, arg: int):
        returnerar -arg

    @neg.register
    @klassmetod
    def _(cls, arg: bool):
        returnerar inte arg

Samma mönster kan användas för andra liknande dekoratorer: @staticmethod, @abstractmethod, och andra.

Tillagd i version 3.8.

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

Uppdaterar en omslagsfunktion så att den ser ut som den omhöljda funktionen. De valfria argumenten är tupler som anger vilka attribut i originalfunktionen som tilldelas direkt till de matchande attributen i omslagsfunktionen och vilka attribut i omslagsfunktionen som uppdateras med motsvarande attribut från originalfunktionen. Standardvärdena för dessa argument är modulnivåkonstanterna WRAPPER_ASSIGNMENTS (som tilldelar omslagsfunktionens __module__, __name__, __qualname__, __annotations__, __type_params__, och __doc__, dokumentationssträngen) och WRAPPER_UPDATES (som uppdaterar omslagsfunktionens __dict__, dvs. instansordboken).

För att tillåta åtkomst till originalfunktionen för introspektion och andra ändamål (t.ex. kringgå en cachningsdekorator som lru_cache()), lägger denna funktion automatiskt till ett __wrapped__-attribut till omslaget som refererar till den funktion som omslaget avser.

Den här funktionen är främst avsedd att användas i decorator-funktioner som omsluter den dekorerade funktionen och returnerar omslaget. Om omslutningsfunktionen inte uppdateras kommer metadata för den returnerade funktionen att återspegla omslutningsdefinitionen snarare än den ursprungliga funktionsdefinitionen, vilket vanligtvis inte är till någon större hjälp.

update_wrapper() kan användas med andra anropbara objekt än funktioner. Alla attribut som namnges i assigned eller updated som saknas från objektet som omsluts ignoreras (dvs. denna funktion kommer inte att försöka ställa in dem på omslutningsfunktionen). AttributeError utlöses fortfarande om omslutningsfunktionen själv saknar några attribut som namnges i updated.

Ändrad i version 3.2: Attributet __wrapped__ läggs nu till automatiskt. Attributet __annotations__ kopieras nu som standard. Saknade attribut utlöser inte längre ett AttributeError.

Ändrad i version 3.4: Attributet __wrapped__ hänvisar nu alltid till den inkapslade funktionen, även om den funktionen definierade attributet __wrapped__. (se bpo-17482)

Ändrad i version 3.12: Attributet __type_params__ kopieras nu som standard.

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

Detta är en bekvämlighetsfunktion för att anropa update_wrapper() som en funktionsdekorator när man definierar en omslagsfunktion. Den är likvärdig med partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated). Till exempel:

>>> 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'

Utan denna dekoratorfabrik skulle namnet på exempelfunktionen ha varit 'wrapper', och dokumentsträngen för den ursprungliga example() skulle ha gått förlorad.

partial Objekt

partial-objekt är anropsbara objekt som skapas av partial(). De har tre skrivskyddade attribut:

partial.func

Ett anropsbart objekt eller en funktion. Anrop till objektet partial kommer att vidarebefordras till func med nya argument och nyckelord.

partial.args

De positionella argument längst till vänster som kommer att läggas till de positionella argument som anges i ett partial-objektanrop.

partial.keywords

De nyckelordsargument som kommer att anges när objektet partial anropas.

partial-objekt är som funktionsobjekt i det att de är anropsbara, svagt refererbara och kan ha attribut. Det finns några viktiga skillnader. Exempelvis skapas inte attributen __name__ och __doc__ automatiskt.