Python Language
Lista förstörande (aka packning och packning)
Sök…
Destruktureringsuppdrag
I uppdrag kan du dela upp en Iterable i värden med syntaxen "packa upp":
Destrukturering som värden
a, b = (1, 2)
print(a)
# Prints: 1
print(b)
# Prints: 2
Om du försöker packa upp mer än den iterbara längden får du ett fel:
a, b, c = [1]
# Raises: ValueError: not enough values to unpack (expected 3, got 1)
Destrukturering som en lista
Du kan packa upp en lista med okänd längd med följande syntax:
head, *tail = [1, 2, 3, 4, 5]
Här extraherar vi det första värdet som en skalar och de andra värdena som en lista:
print(head)
# Prints: 1
print(tail)
# Prints: [2, 3, 4, 5]
Vilket motsvarar:
l = [1, 2, 3, 4, 5]
head = l[0]
tail = l[1:]
Det fungerar också med flera element eller element i slutet av listan:
a, b, *other, z = [1, 2, 3, 4, 5]
print(a, b, z, other)
# Prints: 1 2 5 [3, 4]
Att ignorera värden vid förstörande uppdrag
Om du bara är intresserad av ett visst värde kan du använda _
att indikera att du inte är intresserad. Obs: detta ställer fortfarande _
, bara de flesta använder inte det som en variabel.
a, _ = [1, 2]
print(a)
# Prints: 1
a, _, c = (1, 2, 3)
print(a)
# Prints: 1
print(c)
# Prints: 3
Att ignorera listor i förstörande uppdrag
Slutligen kan du ignorera många värden med hjälp av *_
syntaxen i uppdraget:
a, *_ = [1, 2, 3, 4, 5]
print(a)
# Prints: 1
vilket inte är riktigt intressant, eftersom du istället kan använda indexering på listan. Där det blir trevligt är att behålla första och sista värden i en uppgift:
a, *_, b = [1, 2, 3, 4, 5]
print(a, b)
# Prints: 1 5
eller extrahera flera värden samtidigt:
a, _, b, _, c, *_ = [1, 2, 3, 4, 5, 6]
print(a, b, c)
# Prints: 1 3 5
Packningsfunktionsargument
I funktioner kan du definiera ett antal obligatoriska argument:
def fun1(arg1, arg2, arg3):
return (arg1,arg2,arg3)
vilket gör att funktionen endast kan kallas när de tre argumenten ges:
fun1(1, 2, 3)
och du kan definiera argumenten som valfria genom att använda standardvärden:
def fun2(arg1='a', arg2='b', arg3='c'):
return (arg1,arg2,arg3)
så du kan ringa funktionen på många olika sätt, som:
fun2(1) → (1,b,c)
fun2(1, 2) → (1,2,c)
fun2(arg2=2, arg3=3) → (a,2,3)
...
Men du kan också använda den förstörande syntaxen för att packa upp argument, så att du kan tilldela variabler med hjälp av en list
eller en dict
.
Packa en lista med argument
Tänk på att du har en lista med värden
l = [1,2,3]
Du kan anropa funktionen med listan över värden som ett argument med *
syntax:
fun1(*l)
# Returns: (1,2,3)
fun1(*['w', 't', 'f'])
# Returns: ('w','t','f')
Men om du inte tillhandahåller en lista med längden som matchar antalet argument:
fun1(*['oops'])
# Raises: TypeError: fun1() missing 2 required positional arguments: 'arg2' and 'arg3'
Packning av nyckelordargument
Nu kan du också packa argument med en ordlista. Du kan använda operatören **
att berätta för Python att packa upp dict
som parametervärden:
d = {
'arg1': 1,
'arg2': 2,
'arg3': 3
}
fun1(**d)
# Returns: (1, 2, 3)
när funktionen bara har positionsargument (de utan standardvärden) behöver du att ordboken ska innehålla alla förväntade parametrar och inte har någon extra parameter, eller så får du ett fel:
fun1(**{'arg1':1, 'arg2':2})
# Raises: TypeError: fun1() missing 1 required positional argument: 'arg3'
fun1(**{'arg1':1, 'arg2':2, 'arg3':3, 'arg4':4})
# Raises: TypeError: fun1() got an unexpected keyword argument 'arg4'
För funktioner som har valfria argument kan du packa argumenten som en ordbok på samma sätt:
fun2(**d)
# Returns: (1, 2, 3)
Men där kan du utelämna värden, eftersom de kommer att ersättas med standardvärdena:
fun2(**{'arg2': 2})
# Returns: ('a', 2, 'c')
Och på samma sätt som tidigare kan du inte ge extravärden som inte är existerande parametrar:
fun2(**{'arg1':1, 'arg2':2, 'arg3':3, 'arg4':4})
# Raises: TypeError: fun2() got an unexpected keyword argument 'arg4'
Vid användning i verklig värld kan funktioner ha både positionella och valfria argument, och det fungerar på samma sätt:
def fun3(arg1, arg2='b', arg3='c')
return (arg1, arg2, arg3)
du kan ringa funktionen med bara en iterable:
fun3(*[1])
# Returns: (1, 'b', 'c')
fun3(*[1,2,3])
# Returns: (1, 2, 3)
eller med bara en ordlista:
fun3(**{'arg1':1})
# Returns: (1, 'b', 'c')
fun3(**{'arg1':1, 'arg2':2, 'arg3':3})
# Returns: (1, 2, 3)
eller så kan du använda båda i samma samtal:
fun3(*[1,2], **{'arg3':3})
# Returns: (1,2,3)
Se dock till att du inte kan tillhandahålla flera värden för samma argument:
fun3(*[1,2], **{'arg2':42, 'arg3':3})
# Raises: TypeError: fun3() got multiple values for argument 'arg2'
Packa upp funktionsargument
När du vill skapa en funktion som kan acceptera valfritt antal argument och inte säkerställa positionens eller namnet på argumentet vid "kompilera" tid, är det möjligt och så här:
def fun1(*args, **kwargs):
print(args, kwargs)
*args
och **kwargs
är specialparametrar som är inställda på en tuple
respektive en dict
:
fun1(1,2,3)
# Prints: (1, 2, 3) {}
fun1(a=1, b=2, c=3)
# Prints: () {'a': 1, 'b': 2, 'c': 3}
fun1('x', 'y', 'z', a=1, b=2, c=3)
# Prints: ('x', 'y', 'z') {'a': 1, 'b': 2, 'c': 3}
Om du tittar på tillräckligt med Python-kod kommer du snabbt att upptäcka att den används allmänt när du överför argument till en annan funktion. Om du till exempel vill utöka strängklassen:
class MyString(str):
def __init__(self, *args, **kwarg):
print('Constructing MyString')
super(MyString, self).__init__(*args, **kwarg)