Hvordan bruger man udpakningsoperatørerne (*, **) i Python?

Python er det mest brugte programmeringssprog. I dag vil du lære at bruge en af ​​dens kerne – men ofte ignoreret – funktioner, udpakning i Python.

Du har sikkert set * og ** i andres kode eller endda brugt dem uden egentlig at vide, hvad deres formål er. Vi vil gennemgå konceptet med udpakning, og hvordan man bruger det til at skrive mere Pythonic-kode.

Her er en liste over begreber, som du vil finde nyttige, mens du læser denne vejledning:

  • Iterable: Enhver sekvens, der kan itereres af en for-loop, såsom sæt, lister, tupler og ordbøger
  • Callable: Et Python-objekt, der kan kaldes ved hjælp af dobbelt parentes (), for eksempel myfunction()
  • Shell: Interaktivt runtime-miljø, som lader os køre Python-kode. Vi kan kalde det ved at køre “python” i en terminal
  • Variabel: Symbolsk navn, der gemmer et objekt og har en reserveret hukommelsesplacering.

Lad os starte med den hyppigste forvirring: Asteristik i Python er også aritmetiske operatorer. En stjerne

bruges til multiplikation, mens to af dem (**) refererer til eksponentiering.

>>> 3*3
9
>>> 3**3
27

Vi kan bevise det ved at åbne en Python-skal og skrive:

Bemærk: Du skal have Python 3 installeret for at følge med i denne tutorial. Hvis du ikke har det installeret, tjek vores Python installationsvejledning.

Som du kan se, bruger vi stjernen efter det første tal og før det andet. Når du ser dette, betyder det, at vi bruger de aritmetiske operatorer.

>>> *range(1, 6),
(1, 2, 3, 4, 5)
>>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2}
{'vanilla': 3, 'chocolate': 2, 'strawberry': 2}

På den anden side bruger vi stjernerne (*, **) før en iterable til at pakke den ud – for eksempel:

Bare rolig, hvis du ikke forstår det, dette er blot en indledning til udpakning i Python. Så gå videre og læs hele vejledningen!

Hvad pakker ud?

Udpakning er processen med at få ting ud – iterables såsom lister, tupler og ordbøger. Tænk på det som at åbne en boks og få forskellige ting ud som kabler, hovedtelefoner eller en USB.

  Alt hvad du behøver at vide om den nye iPad-mus og pegefeltmarkør

Udpakning i Python svarer til at pakke en kasse ud i det virkelige liv.

>>> mybox = ['cables', 'headphones', 'USB']
>>> item1, item2, item3 = mybox

Lad os oversætte det samme eksempel til kode for en bedre forståelse:

Som du kan se, tildeler vi de tre elementer inde i mybox-listen til tre variabler item1, item2, item2. Denne form for variabel tildeling er det grundlæggende koncept for udpakning i Python.

>>> item1
'cables'
>>> item2
'headphones'
>>> item3
'USB'

Hvis du forsøger at få værdien af ​​hver genstand, vil du bemærke, at item1, refererer til “kabler”, item2, refererer til “hovedtelefoner” og så videre.

>>> newbox = ['cables', 'headphones', 'USB', 'mouse']
>>> item1, item2, item3 = newbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

Indtil her ser alt ud til at være fint med denne kode, men hvad nu hvis vi ville pakke en liste ud med flere elementer i den – og beholde den samme mængde af tildelte variabler?

Det er sandsynligvis du forventede denne form for fejl. I bund og grund tildeler vi 4 listeelementer til tre variabler, hvordan klarer Python at tildele de rigtige værdier? Det gør det ikke, det er fordi vi får en ValueError

med beskeden “for mange værdier til at pakke ud”. Dette sker, fordi vi indstiller tre variabler til venstre og fire værdier (svarende til newbox-listen) til højre.

>>> lastbox = ['cables', 'headphones']
>>> item1, item2, item3 = lastbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)

Hvis du prøver at udføre en lignende proces, men med flere variabler end værdier, der skal pakkes ud, får du en anden ValueError bortset fra den med en lidt anden besked:

Bemærk: Vi har arbejdet med lister, men du kan bruge denne form for udpakning med enhver iterable (lister, sæt, tupler, ordbøger)

Så hvordan overvinder vi denne situation? Er der nogen måde at udpakke alle elementerne i en iterable til et par variabler uden at få nogen fejl?

Ja, det er der, og det kaldes udpakningsoperatør eller stjerneoperatør (*, **). Lad os se, hvordan du bruger det i Python.

Sådan pakkes lister ud med *-operatøren

Stjerneoperatøren

>>> first, *unused, last = [1, 2, 3, 5, 7]
>>> first
1
>>> last
7
>>> unused
[2, 3, 5]

bruges til at udpakke alle værdierne af en iterable, som ikke er blevet tildelt endnu.

>>> first, *_, last = [1, 2, 3, 5, 7]
>>> _
[2, 3, 5]

Lad os antage, at du vil have det første og sidste element i en liste uden at bruge indekser, vi kunne gøre det med stjerneoperatoren:

>>> first, *_, last = [1, 2]
>>> first
1
>>> last
2
>>> _
[]

Som du kan forstå, får vi alle de ubrugte værdier med asterisk-operatoren. Den foretrukne måde at kassere værdier på er at bruge en understregningsvariabel (_), som nogle gange bruges som en “dummy-variabel”.

  Sådan bruges Animoji som klistermærker på iPhone X

Vi kan stadig bruge dette trick, selvom listen kun har to elementer:

I dette tilfælde gemmer understregningsvariablen (dummy-variabelen) en tom liste, så de to andre variabler omkring dem kan få adgang til de tilgængelige værdier på listen.

>>> *string = 'PythonIsTheBest'

Almindelig fejlfinding

>>> *string = 'PythonIsTheBest'
  File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple

Vi kan udpakke et unikt element af en iterable. For eksempel ville du finde på noget som dette: Ovenstående kode vil dog returnere en SyntaxError:Dette fordi der ifølge

PEP-specifikation

:

>>> *string, = 'PythonIsTheBest'
>>> string
['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']

En tuple (eller liste) i venstre side af en simpel opgave

>>> *numbers, = range(5)
>>> numbers
[0, 1, 2, 3, 4]

Hvis vi ønsker at pakke alle værdierne af en iterabel ud til en enkelt variabel, skal vi opsætte en tupel, derfor vil det være nok at tilføje et simpelt komma:

Et andet eksempel ville være at bruge rækkeviddefunktionen, som returnerer en række tal.

Nu hvor du ved, hvordan du pakker lister og tupler ud med en stjerne, er det tid til at komme ind i udpakning af ordbøger.

Sådan pakkes ordbøger ud med **-operatøren

>>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} 
...
SyntaxError: invalid syntax

Mens en enkelt stjerne bruges til at udpakke lister og tupler, bruges dobbeltstjernen (**) til at pakke ordbøger ud.

>>> food = {'fish':3, 'meat':5, 'pasta':9} 
>>> colors = {'red': 'intensity', 'yellow':'happiness'}
>>> merged_dict = {**food, **colors}
>>> merged_dict
{'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}

Desværre kan vi ikke pakke en ordbog ud til en enkelt variabel, som vi har gjort med tupler og lister. Det betyder, at følgende vil give en fejl:

Vi kan dog bruge **-operatøren inde i callables og andre ordbøger. For eksempel, hvis vi ønsker at oprette en fusioneret ordbog, lavet af andre ordbøger, kan vi bruge koden nedenfor:

Dette er en ret kort måde at skabe sammensatte ordbøger på, men dette er ikke hovedmetoden til udpakning i Python.

Lad os se, hvordan vi kan bruge udpakning med callables

Pakning i funktioner: args og kwargs

Du har sikkert set args og kwargs før enten implementeret på klasser eller funktioner. Lad os se, hvorfor vi skal bruge dem sammen med callables.

>>> def product(n1, n2):
...     return n1 * n2
... 
>>> numbers = [12, 1]
>>> product(*numbers)
12

Pakning med *-operatøren (args)

>>> product(12, 1)
12

Antag, at vi har en funktion, der beregner produktet af to tal.

>>> numbers = [12, 1, 3, 4]
>>> product(*numbers)
...
TypeError: product() takes 2 positional arguments but 4 were given

Som du kan se, pakker vi listenumrene ud til funktionen, så vi kører faktisk følgende:

>>> def product(*args):
...     result = 1
...     for i in args:
...             result *= i
...     return result
...
>>> product(*numbers)
144

Indtil her fungerer alt fint, men hvad nu hvis vi ville bestå en længere liste? Det vil helt sikkert rejse en fejl, fordi funktionen modtager flere argumenter, end den er i stand til at håndtere.

  9 private World of Warcraft-servere (WOW) at deltage i

Vi kan løse alt dette blot ved at pakke listen direkte på funktionen, hvilket skaber en iterabel inde i den og giver os mulighed for at sende et vilkårligt antal argumenter til funktionen.

Her behandler vi args-parameteren som en iterabel, går på tværs af dens elementer og returnerer produktet af alle tallene. Bemærk hvordan starttallet for resultatet skal være et, for hvis vi starter med nul, vil funktionen altid returnere nul. Bemærk: args er kun en konvention, du kan bruge et hvilket som helst andet parameternavnVi kunne også sende vilkårlige tal til funktionen uden at bruge en liste, ligesom med den indbyggede

>>> product(5, 5, 5)
125
>>> print(5, 5, 5)
5 5 5

print funktion

>>> def test_type(*args):
...     print(type(args))
...     print(args)
... 
>>> test_type(1, 2, 4, 'a string')
<class 'tuple'>
(1, 2, 4, 'a string')

.

Lad os endelig få objekttypen for en funktions args.

Som bemærket i ovenstående kode, vil typen af ​​args altid være tuple, og indholdet af det vil være alle de ikke-nøgleordede argumenter, der sendes til funktionen.

Pakning med **-operatøren (kwargs)

>>> def make_person(name, **kwargs):
...     result = name + ': '
...     for key, value in kwargs.items():
...             result += f'{key} = {value}, '
...     return result
... 
>>> make_person('Melissa', id=12112, location='london', net_worth=12000)
'Melissa: id = 12112, location = london, net_worth = 12000, '

Som vi så tidligere, bruges **-operatoren udelukkende til ordbøger. Det betyder, at vi med denne operator er i stand til at overføre nøgleværdi-par til funktionen som en parameter.

Lad os oprette en funktion make_person, som modtager et positionsargument “navn” og en udefineret mængde af nøgleordsargumenter.

Som du kan se, konverterer **kwargs-sætningen alle søgeordsargumenter til en ordbog, som vi kan iterere inde i funktionen.

>>> def test_kwargs(**kwargs):
...     print(type(kwargs))
...     print(kwargs)
... 
>>> test_kwargs(random=12, parameters=21)
<class 'dict'>
{'random': 12, 'parameters': 21}

Bemærk: kwargs er kun en konvention, du kan navngive denne parameter med hvad du vil

Vi kan kontrollere typen af ​​kwargs på samme måde, som vi gjorde med args:

>>> def my_final_function(*args, **kwargs):
...     print('Type args: ', type(args))
...     print('args: ', args)
...     print('Type kwargs: ', type(kwargs))
...     print('kwargs: ', kwargs)
... 
>>> my_final_function('Python', 'The', 'Best', language="Python", users="A lot")
Type args:  <class 'tuple'>
args:  ('Python', 'The', 'Best')
Type kwargs:  <class 'dict'>
kwargs:  {'language': 'Python', 'users': 'A lot'}

Kwargs interne variabel bliver altid til en ordbog, som gemmer nøgleværdi-parrene, der sendes til funktionen.

Lad os endelig gøre brug af args og kwargs i samme funktion:

Konklusion

  • Udpakningsoperatører er virkelig nyttige i daglige opgaver, nu ved du, hvordan du bruger dem både i individuelle udsagn og funktionsparametre.
  • I denne tutorial lærte du:
  • Du bruger * til tupler og lister og ** til ordbøger
  • Du kan bruge udpakningsoperatorer i funktions- og klassekonstruktører

args bruges til at videregive parametre uden nøgleord til funktionerkwargs bruges til at videregive nøgleordede parametre til funktioner.