Kurzusok
/
Python
Python
/
Tanterv
/
Kicsomagolás és többszörös értékadás
Ki

Kicsomagolás és többszörös értékadás ebben a kurzusban: Python

3 feladat

A(z) Kicsomagolás és többszörös értékadás fogalomról

A kicsomagolás során egy gyűjtemény, például egy list, tuple vagy dict elemeit nyerjük ki iterációval. A kicsomagolt értékeket ezután ugyanabban az utasításban értékül adhatjuk változóknak. Ennek a viselkedésnek nagyon gyakori példája a for item in list, ahol az item az iteráció során sorban felveszi az egyes list-elemek értékét.

A többszörös értékadás lehetővé teszi, hogy egyetlen utasításban több változónak adjunk kicsomagolt értékeket. Ettől a kód tömörebb és olvashatóbb lesz, és úgy csináljuk, hogy a hozzárendelendő változókat vesszővel választjuk el, például first, second, third = (1,2,3) vagy for index, item in enumerate(iterable).

A * és a ** speciális operátort gyakran használjuk kicsomagolási helyzetekben. A * segítségével több list-et/tuple-t egyetlen list-té/tuple-vé kombinálhatunk úgy, hogy mindegyiket kicsomagoljuk egy új, közös list-be/tuple-be. A ** segítségével több szótárat egyetlen szótárrá kombinálhatunk úgy, hogy mindegyiket kicsomagoljuk egy új, közös dict-be.

Amikor a * operátort gyűjtemény nélkül használjuk, akkor becsomagol több értéket egy list-be. Ezt gyakran használjuk többszörös értékadásnál arra, hogy egyetlen változóba gyűjtsük az összes „maradék” elemet, amelyekhez nem tartozik külön értékadás.

Pythonban gyakori, hogy ezt a kicsomagoló/becsomagoló viselkedést függvények használatakor vagy definiálásakor is kihasználjuk, ha azok tetszőleges számú pozicionális vagy kulcsszavas argumentumot fogadnak. Gyakran láthatod, hogy ezeket a „speciális” paramétereket így definiálják: def some_function(*args, **kwargs), a „speciális” argumentumokat pedig így használják: some_function(*some_tuple, **some_dict).

Caution

A *<variable_name> és a **<variable_name> nem tévesztendő össze a * és a ** operátorral. Míg a * és a ** rendre a szorzásra és a hatványozásra szolgál, addig a *<variable_name> és a **<variable_name> a csomagolás és a kicsomagolás operátora.

Többszörös értékadás

Többszörös értékadásnál a hozzárendelés-operátor (=) bal oldalán álló változók számának meg kell egyeznie a jobb oldalon álló értékek számával. Az értékeket vesszővel (,) válaszd el:

>>> a, b = 1, 2
>>> a
1

Ha a többszörös értékadásnál nem megfelelő számú változót adunk meg az értékekhez, ValueError keletkezik:

>>> x, y, z = 1, 2

ValueError: too many values to unpack (expected 3, got 2)

A többszörös értékadás nem korlátozódik egyetlen adattípusra:

>>> x, y, z = 1, "Hello", True
>>> x
1

>>> y
'Hello'

>>> z
True

A többszörös értékadással lists-ben is felcserélhetjük az elemeket. Ez a gyakorlat meglehetősen gyakori a rendezési algoritmusokban. Például:

>>> numbers = [1, 2]
>>> numbers[0], numbers[1] = numbers[1], numbers[0]
>>> numbers
[2, 1]

Mivel a tuples változtathatatlan, egy tuple elemeit nem cserélheted fel.

Kicsomagolás

Note

Az alábbi példákban lists szerepel, de ugyanezek a fogalmak a tuples-re is érvényesek.

Pythonban lehetőség van arra, hogy kicsomagoljuk egy list/tuple/dict elemeit különálló változókba. Mivel az értékek meghatározott sorrendben szerepelnek a lists/tuples-ben, ugyanabban a sorrendben csomagoljuk ki őket a változókba:

>>> fruits = ["apple", "banana", "cherry"]
>>> x, y, z = fruits
>>> x
"apple"

Ha vannak olyan értékek, amelyekre nincs szükség, akkor a _ jellel jelölheted őket:

>>> fruits = ["apple", "banana", "cherry"]
>>> _, _, z = fruits
>>> z
"cherry"

Mély kicsomagolás

A list/tuple értékeinek kicsomagolása és értékül adása egy másik list-en vagy tuple-ön belül (más néven egymásba ágyazott listák/tuple-ök) ugyanúgy működik, mint a sekély kicsomagolás, de gyakran szükség van pontosításra az érték kontextusát vagy pozícióját illetően:

>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [[a, b], [c, d]] = fruits_vegetables
>>> a
"apple"

>>> d
"potato"

Egy egymásba ágyazott list/tuple akár csak egy részét is kicsomagolhatod mélyen:

>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [a, [c, d]] = fruits_vegetables
>>> a
["apple", "banana"]

>>> c
"carrot"

Ha a kicsomagolásnál a változók elhelyezkedése hibás, illetve az értékek száma nem megfelelő, ValueError-t kapsz:

>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [[a, b], [d]] = fruits_vegetables

ValueError: too many values to unpack (expected 1)

Lista/tuple kicsomagolása a * operátorral

Amikor kicsomagolsz egy list/tuple-t, a * operátorral elkaphatod a „maradék” értékeket. Ez áttekinthetőbb, mint a list/tuple szeletelése (ami bizonyos helyzetekben kevésbé olvasható). Például kinyerhetjük az első elemet, a maradék értékeket pedig becsomagolhatjuk egy új list-be, amely nem tartalmazza az első elemet:

>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>>> x, *last = fruits
>>> x
"apple"

>>> last
["banana", "cherry", "orange", "kiwi", "melon", "mango"]

Kinyerhetjük a list elején és végén lévő értékeket is, miközben a középső értékeket egy csoportba gyűjtjük:

>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>>> x, *middle, y, z = fruits
>>> y
"melon"

>>> middle
["banana", "cherry", "orange", "kiwi"]

A *-ot mély kicsomagolásnál is használhatjuk:

>>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
>>> [[a, *rest], b] = fruits_vegetables
>>> a
"apple"

>>> rest
["banana", "melon"]

Szótár kicsomagolása

A szótár kicsomagolása kicsit más, mint egy list/tuple kicsomagolása. A szótárakon végzett iteráció alapértelmezésben a kulcsokat adja. Ezért amikor egy dict-et csomagolsz ki, csak a kulcsokat tudod kicsomagolni, az értékeket nem:

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory
>>> x
"apple"

Ha az értékeket is ki szeretnéd csomagolni, használhatod a <dict>.values() metódust:

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory.values()
>>> x
6

Ha egyszerre van szükség a kulcsokra és az értékekre, használd a <dict>.items() metódust. A <dict>.items() egy iterálható nézetet hoz létre, amely kulcs-érték párokat tartalmaz. Ezek egy tuple-be csomagolhatók ki:

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory.items()
>>> x
("apple", 6)

Csomagolás

A csomagolás segítségével több értéket gyűjthetünk egyetlen list-be, amelyet egy változónak adunk értékül. Ez akkor hasznos, ha ki szeretnéd csomagolni az értékeket, módosítani szeretnéd őket, majd az eredményt vissza csomagolni egy változóba. Arra is lehetőséget ad, hogy két vagy több lists/tuples/dicts tartalmát összefésüljük.

Lista/tuple csomagolása a * operátorral

Egy list/tuple csomagolását a * operátorral végezhetjük el. Ez az összes értéket egy list-be/tuple-be csomagolja.

>>> fruits = ("apple", "banana", "cherry")
>>> more_fruits = ["orange", "kiwi", "melon", "mango"]

# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
>>> combined_fruits = *fruits, *more_fruits

# If there is no * on to the left of the "=" the result is a tuple
>>> combined_fruits
("apple", "banana", "cherry", "orange", "kiwi", "melon", "mango")

# If the * operator is used on the left side of "=" the result is a list.
# Note the trailing comma. 
>>> *combined_fruits_too, = *fruits, *more_fruits
>>> combined_fruits_too
['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']

# A list literal can be used instead, but might not be as readable.
>>> [*combined_fruits_too] = *fruits, *more_fruits
>>> combined_fruits_too
['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']

A * és a ** használatáról bővebben a PEP 3132 és a PEP 448 dokumentumban olvashatsz.

Szótár csomagolása a ** operátorral

A szótár csomagolását a ** operátorral végezzük. Ez az egyik szótár összes kulcs-érték párját egy másik szótárba csomagolja, vagy két szótárat egyesít.

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3}

# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
>>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}

# then the pairs are packed into combined_fruits_inventory
>>> combined_fruits_inventory
{"apple": 6, "banana": 2, "cherry": 3, "orange": 4, "kiwi": 1, "melon": 2, "mango": 3}

A * és a ** használata függvényekkel

Csomagolás függvényparaméterekkel

Amikor olyan függvényt hozol létre, amely tetszőleges számú argumentumot fogad, a függvény definíciójában használhatod a *args vagy **kwargs paramétereket. A *args tetszőleges számú pozicionális (nem kulcsszavas) argumentum becsomagolására szolgál, a **kwargs pedig tetszőleges számú kulcsszavas argumentum becsomagolására.

A *args használata:

# This function is defined to take any number of positional arguments

>>> def my_function(*args):
...   print(args)

# Arguments given to the function are packed into a tuple

>>> my_function(1, 2, 3)
(1, 2, 3)

>>> my_function("Hello")
("Hello")

>>> my_function(1, 2, 3, "Hello", "Mars")
(1, 2, 3, "Hello", "Mars")

A **kwargs használata:

# This function is defined to take any number of keyword arguments

>>> def my_function(**kwargs):
...   print(kwargs)

# Arguments given to the function are packed into a dictionary

>>> my_function(a=1, b=2, c=3)
{"a": 1, "b": 2, "c": 3}

A *args és a **kwargs egymással kombinálva is használható:

>>> def my_function(*args, **kwargs):
...   print(sum(args))
...   for key, value in kwargs.items():
...       print(str(key) + " = " + str(value))

>>> my_function(1, 2, 3, a=1, b=2, c=3)
6
a = 1
b = 2
c = 3

Írhatsz paramétereket a *args elé is, hogy meghatározott pozicionális argumentumokat engedj meg. Az egyes kulcsszavas argumentumoknak ekkor a **kwargs előtt kell szerepelniük.

Caution

Az argumentumokat a következő sorrendben kell elhelyezni:

def my_function(<positional_args>, *args, <key-word_args>, **kwargs)

Ha nem tartod be ezt a sorrendet, hibát kapsz.

>>> def my_function(a, b, *args):
...   print(a)
...   print(b)
...   print(args)

>>> my_function(1, 2, 3, 4, 5)
1
2
(3, 4, 5)

Ha az argumentumokat rossz sorrendben írod le, hibaüzenetet kapsz:

>>> def my_function(*args, a, b):
...   print(args)

>>>my_function(1, 2, 3, 4, 5)
Traceback (most recent call last):
  File "c:\something.py", line 3, in <module>
    my_function(1, 2, 3, 4, 5)
TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b'

Kicsomagolás függvényhívásokba

A * segítségével egy list/tuple argumentumait csomagolhatod ki egy függvényhívásba. Ez nagyon hasznos azoknál a függvényeknél, amelyek nem fogadnak el iterable-t:

>>> def my_function(a, b, c):
...   print(c)
...   print(b)
...   print(a)

numbers = [1, 2, 3]
>>> my_function(*numbers)
3
2
1

A * operátorral való kicsomagolás a zip() beépített függvénnyel szintén gyakori felhasználási eset. A zip() függvény több iterálható objektumot vesz át, és egy list-et ad vissza, amely tuples-ekből áll, az egyes iterable-ek értékeit csoportosítva:

>>> values = (['x', 'y', 'z'], [1, 2, 3], [True, False, True])
>>> a, *rest = zip(*values)
>>> rest
[('y', 2, False), ('z', 3, True)]
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Kicsomagolás és többszörös értékadás fogalmat

A gyakorlás zárolva

Oldj fel még 3 feladatot, hogy gyakorolhasd a(z) Kicsomagolás és többszörös értékadás fogalmat