Cum să utilizați operatorii de despachetare (*, **) în Python?

Python este cel mai folosit limbaj de programare. Astăzi veți învăța să utilizați una dintre caracteristicile sale de bază, dar adesea ignorate, despachetarea în Python.

Probabil ați văzut * și ** în codul altora sau chiar le-ați folosit fără să știți care este scopul lor. Vom parcurge conceptul de despachetare și cum să îl folosim pentru a scrie mai mult cod Pythonic.

Iată o listă de concepte pe care le veți găsi utile în timp ce citiți acest tutorial:

  • Iterabil: orice secvență care poate fi iterată printr-o buclă for, cum ar fi seturi, liste, tupluri și dicționare
  • Apelabil: un obiect Python care poate fi apelat folosind paranteze duble (), de exemplu, myfunction()
  • Shell: mediu de rulare interactiv care ne permite să rulăm cod Python. Îl putem numi rulând „python” într-un terminal
  • Variabilă: nume simbolic care stochează un obiect și are o locație de memorie rezervată.

Să începem cu cea mai frecventă confuzie: asteristicile din Python sunt, de asemenea, operatori aritmetici. Un asterisc

este folosit pentru înmulțire, în timp ce două dintre ele (**) se referă la exponențiere.

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

Putem demonstra că deschizând un shell Python și tastând:

Notă: Trebuie să aveți instalat Python 3 pentru a urma acest tutorial. Dacă nu îl aveți instalat, consultați ghidul nostru de instalare Python.

După cum puteți vedea, folosim asteriscul după primul număr și înainte de al doilea. Când vedeți asta, înseamnă că folosim operatorii aritmetici.

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

Pe de altă parte, folosim asteriscurile (*, **) înaintea unui iterabil pentru a-l despacheta – de exemplu:

Nu vă faceți griji dacă nu îl primiți, acesta este doar un preambul pentru despachetarea în Python. Așa că mergeți mai departe și citiți întregul tutorial!

Ce despachetează?

  Ce se întâmplă dacă contul tău Uber este dezactivat definitiv?

Dezambalarea este procesul de a scoate lucruri — iterabile, cum ar fi liste, tupluri și dicționare. Gândiți-vă la asta ca la deschiderea unei cutii și la scoaterea diferitelor articole precum cabluri, căști sau un USB.

Dezambalarea în Python este similară cu despachetarea unei cutii în viața reală.

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

Să traducem același exemplu în cod pentru o mai bună înțelegere:

După cum puteți vedea, atribuim cele trei elemente din lista mybox la trei variabile item1, item2, item2. Acest tip de atribuire a variabilelor este conceptul fundamental de despachetare în Python.

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

Dacă încercați să obțineți valoarea fiecărui articol, veți observa că elementul1, se referă la „cabluri”, articolul2, se referă la „căști” și așa mai departe.

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

Până aici, totul pare să fie în regulă cu acest cod, dar dacă am dori să despachetăm o listă cu mai multe elemente în ea – păstrând aceeași cantitate de variabile alocate?

Probabil te așteptai la acest tip de eroare. În esență, atribuim 4 elemente de listă la trei variabile, cum reușește Python să atribuie valorile potrivite? Nu, asta pentru că primim un ValueError

cu mesajul „prea multe valori de despachetat”. Acest lucru se întâmplă deoarece setăm trei variabile în stânga și patru valori (corespunzând listei newbox) în dreapta.

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

Dacă încercați să faceți un proces similar, dar cu mai multe variabile decât valori de despachetat, veți primi o altă ValueError, cu excepția faptului că cu un mesaj ușor diferit:

Notă: am lucrat cu liste, dar puteți utiliza această formă de despachetare cu orice iterabil (liste, seturi, tupluri, dicționare)

Deci cum depășim această situație? Există vreo modalitate de a despacheta toate elementele unui iterabil la câteva variabile fără a primi erori?

Sigur că există și se numește operator de despachetare sau operator de asterisc (*, **). Să vedem cum să-l folosești în Python.

Cum să despachetezi liste cu operatorul *

Operatorul asterisc

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

este folosit pentru a despacheta toate valorile unui iterabil care nu au fost încă atribuite.

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

Să presupunem că doriți să obțineți primul și ultimul element al unei liste fără a utiliza indecși, am putea face acest lucru cu operatorul asterisc:

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

După cum puteți aprecia, obținem toate valorile neutilizate cu operatorul asterisc. Modul preferat de a renunța la valori este de a folosi o variabilă de subliniere (_), care este uneori folosită ca „variabilă inactivă”.

  Cum să remediați tabelele corupte în MySQL

Putem folosi în continuare acest truc chiar dacă lista are doar două elemente:

În acest caz, variabila subliniere (variabilă inactivă) stochează o listă goală, astfel încât celelalte două variabile din jurul lor să poată accesa valorile disponibile ale listei.

>>> *string = 'PythonIsTheBest'

Depanare comună

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

Putem despacheta un element unic al unui iterabil. De exemplu, ai veni cu ceva de genul acesta: Cu toate acestea, codul de mai sus va returna o SyntaxError:Aceasta pentru că potrivit

Specificația PEP

:

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

Un tuplu (sau listă) în partea stângă a unei sarcini simple

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

Dacă dorim să despachetăm toate valorile unui iterabil într-o singură variabilă, trebuie să setăm un tuplu, prin urmare adăugarea unei simple virgule va fi suficientă:

Un alt exemplu ar fi folosirea funcției interval, care returnează o secvență de numere.

Acum că știți cum să despachetați listele și tuplurile cu un asterisc, este timpul să intrați în despachetarea dicționarelor.

Cum să despachetezi dicționare cu operatorul **

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

În timp ce un singur asterisc este folosit pentru a despacheta liste și tupluri, asteriscul dublu (**) este folosit pentru a despacheta dicționare.

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

Din păcate, nu putem despacheta un dicționar într-o singură variabilă, așa cum am procedat cu tupluri și liste. Asta înseamnă că următoarele vor genera o eroare:

Cu toate acestea, putem folosi operatorul ** în interiorul apelabilelor și al altor dicționare. De exemplu, dacă dorim să creăm un dicționar îmbinat, realizat din alte dicționare, am putea folosi codul de mai jos:

Aceasta este o modalitate destul de scurtă de a crea dicționare compuse, cu toate acestea, aceasta nu este abordarea principală de despachetare în Python.

Să vedem cum putem folosi despachetarea cu apelabile

Ambalare în Funcții: args și kwargs

Probabil ați văzut args și kwargs înainte fie implementate pe clase sau funcții. Să vedem de ce trebuie să le folosim împreună cu apelabile.

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

Împachetarea cu operatorul * (args)

>>> product(12, 1)
12

Să presupunem că avem o funcție care calculează produsul a două numere.

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

După cum puteți vedea, despachetăm numerele listei în funcție, așa că rulăm de fapt următoarele:

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

Până aici, totul merge bine, dar dacă am vrea să trecem pe o listă mai lungă? Cu siguranță va genera o eroare, deoarece funcția primește mai multe argumente decât este capabilă să gestioneze.

  24 de cele mai bune aplicații de sănătate pentru a vă monitoriza starea de bine și a rămâne în formă

Putem rezolva toate acestea doar prin împachetarea listei direct pe funcție, ceea ce creează un iterabil în interiorul acesteia și ne permite să transmitem orice număr de argumente funcției.

Aici tratăm parametrul args ca pe un iterabil, parcurgând elementele sale și returnând produsul tuturor numerelor. Observați cum numărul de pornire al rezultatului trebuie să fie unul, deoarece dacă începem cu zero, funcția va returna întotdeauna zero. Notă: args este doar o convenție, puteți utiliza orice alt nume de parametruDe asemenea, am putea trece numere arbitrare funcției fără a folosi o listă, la fel ca în cazul încorporat

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

functia de imprimare

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

.

În cele din urmă, să obținem tipul de obiect al argumentelor unei funcții.

După cum s-a menționat în codul de mai sus, tipul de argumente va fi întotdeauna tuplu, iar conținutul acestuia va fi toate argumentele non-cheie transmise funcției.

Ambalare cu operatorul ** (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, '

După cum am văzut anterior, operatorul ** este folosit exclusiv pentru dicționare. Aceasta înseamnă că, cu acest operator, putem transmite perechi cheie-valoare funcției ca parametru.

Să creăm o funcție make_person, care primește un argument pozițional „nume” și o cantitate nedefinită de argumente cu cuvinte cheie.

După cum puteți vedea, instrucțiunea **kwargs convertește toate argumentele cu cuvinte cheie într-un dicționar, pe care îl putem itera în interiorul funcției.

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

Notă: kwargs este doar o convenție pe care o puteți numi acest parametru cu orice doriți

Putem verifica tipul kwarg-urilor în același mod în care am făcut-o cu 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'}

Variabila internă kwargs se transformă întotdeauna într-un dicționar, care stochează perechile cheie-valoare transmise funcției.

În cele din urmă, să folosim args și kwargs în aceeași funcție:

Concluzie

  • Operatorii de despachetare sunt cu adevărat utili în sarcinile de zi cu zi, acum știi cum să-i folosești atât în ​​declarații individuale, cât și în parametrii funcției.
  • În acest tutorial ați învățat:
  • Folosiți * pentru tupluri și liste și ** pentru dicționare
  • Puteți folosi operatori de despachetare în constructorii de funcții și clase

arg-urile sunt folosite pentru a transmite funcțiilor parametri care nu sunt formulați cu cheiekwargs sunt folosite pentru a transmite parametrii cu cuvinte cheie la funcții.