Împachetarea și despachetarea
Despachetarea
Despachetarea (unpacking, cunoscută și ca Destructurare) reprezintă distribuirea unei colecții (tuplu, listă etc.) în valori separate.
La fel ca multe alte limbaje de programare, Python suportă conceptul de atribuire multiplă. De exemplu:
x, y = 1, 2
print(x) # 1
print(y) # 2
În acest caz atribuim valori simultan la două variabile. Atribuirea se face pe poziție: variabila x primește valoarea 1, iar variabila y - valoarea 2.
Acest exemplu reprezintă deja o destructurare sau despachetare. Valorile 1, 2 sunt de fapt un tuplu, deoarece virgulele dintre valori indică faptul că este un tuplu. Am putea scrie și astfel:
x, y = (1, 2)
print(x) # 1
print(y) # 2
În orice caz, avem de-a face cu destructurare, unde primul element al tuplului este atribuit primei variabile, al doilea element - celei de-a doua variabile și așa mai departe. Adică distribuirea se face pe poziție.
În mod similar, putem distribui și alte tupluri, de exemplu:
name, age, company = ("Tom", 38, "Google")
print(name) # Tom
print(age) # 38
print(company) # Google
Nu ne limităm doar la tupluri și putem "despacheta" și alte colecții, cum ar fi liste:
people = ["Tom", "Bob", "Sam"]
first, second, third = people
print(first) # Tom
print(second) # Bob
print(third) # Sam
La despachetarea unui dicționar, variabilele primesc cheile dicționarului:
dictionary = {"red": "roșu", "blue": "albastru", "green": "verde"}
r, b, g = dictionary
print(r) # red
print(b) # blue
print(g) # green
# obținem valoarea după cheie
print(dictionary[g]) # verde
Destructurare în cicluri
Ciclurile în Python permit distribuirea colecțiilor în componente separate:
people = [
("Tom", 38, "Google"),
("Bob", 42, "Microsoft"),
("Sam", 29, "JetBrains")
]
for name, age, company in people:
print(f"Name: {name}, Age: {age}, Company: {company}")
Aici parcurgem lista de tupluri people. Fiecare tuplu constă din trei elemente, astfel încât la parcurgere putem să le atribuim variabilelor name, age și company.
Un alt exemplu este funcția enumerate(). Aceasta primește ca parametru o colecție, creează pentru fiecare element un tuplu și returnează un set de astfel de tupluri. Fiecare tuplu conține un index, care crește cu fiecare iterație:
people = ["Tom", "Bob", "Sam"]
for index, name in enumerate(people):
print(f"{index}.{name}")
# rezultat
# 0.Tom
# 1.Bob
# 2.Sam
Ignorarea valorilor
Dacă un anumit element al colecției nu este necesar, de obicei pentru el se definește o variabilă cu numele _ (linie):
person =("Tom", 38, "Google")
name, _, company = person
print(name) # Tom
print(company) # Google
Aici nu ne interesează al doilea element al tuplului, așa că pentru el definim variabila _. Deși, în realitate, _ este un nume valabil, la fel ca name și company:
name, _, company = person
print(_) # 38
Împachetarea valorilor și operatorul *
Operatorul * împachetează valorile într-o colecție. De exemplu:
num1=1
num2=2
num3=3
*numbers,=num1,num2,num3
print(numbers) #[1, 2, 3]
Aici împachetăm valorile din tuplu (num1,num2,num3) într-o listă numbers. Pentru a obține o listă, după numbers se indică o virgulă.
În general, împachetarea este utilizată pentru a colecta valorile rămase după atribuirea rezultatelor destructurării. De exemplu:
head, *tail = [1, 2, 3, 4, 5]
print(head) # 1
print(tail) # [2, 3, 4, 5]
Aici variabila head primește primul element al listei, conform poziției. Toate celelalte elemente sunt atribuite variabilei tail. Astfel, variabila tail va reprezenta o listă cu elementele rămase.
În mod similar, putem obține toate elementele, cu excepția ultimului:
*head, tail = [1, 2, 3, 4, 5]
print(head) # [1, 2, 3, 4]
print(tail) # 5
Sau elementele din mijloc, cu excepția primului și ultimului:
head, *middle, tail = [1, 2, 3, 4, 5]
print(head) # 1
print(middle) # [2, 3, 4]
print(tail) # 5
Sau toate, cu excepția primului și al doilea:
first, second, *other = [1, 2, 3, 4, 5]
print(first) # 1
print(second) # 2
print(other) # [3, 4, 5]
În general, în acest mod putem obține diverse combinații de elemente ale colecției. Și nu doar liste, ci și tupluri, dicționare și alte colecții.
Un alt exemplu - trebuie să obținem doar primul, al treilea și ultimul element, iar celelalte nu ne interesează. În mod obișnuit, ar trebui să definim variabile pentru toate elementele colecției. Totuși, dacă colecția are 100 de elemente și ne trebuie doar trei, nu vom defini toate cele 100 de variabile. În acest caz, putem aplica împachetarea:
first, _, third, *_, last = [1, 2, 3, 4, 5, 6, 7, 8]
print(first) # 1
print(third) # 3
print(last) # 8
Putem, de asemenea, să obținem cheile unui dicționar:
red, *other, green = {"red":"roșu", "blue":"albastru", "yellow":"galben", "green":"verde"}
print(red) # red
print(green) # green
print(other) # ['blue', 'yellow']
Despachetarea și operatorii * și **
Operatorul * împreună cu operatorul ** poate fi utilizat și pentru despachetarea valorilor. Operatorul * este utilizat pentru despachetarea tuplurilor, listelor, șirurilor de caractere, mulțimilor, iar operatorul ** - pentru despachetarea dicționarelor. Acest lucru poate fi deosebit de util când se creează alte colecții pe baza unora existente. De exemplu, despachetarea tuplurilor și listelor:
nums1 = [1, 2, 3]
nums2 = (4, 5, 6)
# despachetăm lista nums1 și tuplul nums2
nums3 = [*nums1, *nums2]
print(nums3) # [1, 2, 3, 4, 5, 6]
Aici despachetăm valorile din lista nums1 și tuplul nums2 și le plasăm în lista nums3.
În mod similar, se pot despacheta dicționarele, doar că se folosește operatorul **:
dictionary1 = {"red":"roșu", "blue":"albastru"}
dictionary2 = {"green":"verde", "yellow":"galben"}
# despachetăm dicționarele
dictionary3 = {**dictionary1, **dictionary2}
print(dictionary3) # {'red': 'roșu', 'blue': 'albastru', 'green': 'verde', 'yellow': 'galben'}