Användning av Pythons listförståelse notation

Företag

I Python är det enkelt att använda list comprehensions notation när man skapar en ny lista.(List comprehensions)

I den här artikeln kommer vi först att diskutera följande

  • Grundläggande typ av notation för listförståelse
  • Notering av listförståelse med villkorlig förgrening genom om
  • Kombination med ternära operatörer (behandling av typen ”om annars”)
  • zip(),enumerate()Kombination med dessa
  • Notation för inklusion i en inbäddad lista.

Därefter kommer vi att förklara hur man kan förstå en lista med hjälp av exempelkoder.

  • Notation för inklusion av uppsättningar.(Set comprehensions)
  • Notation för inklusion i ordboken.(Dict comprehensions)
  • typ av generator(Generator expressions)

Grundläggande typ av notation för listförståelse

Notationen för listförståelse skrivs på följande sätt.

[Expression for Any Variable Name in Iterable Object]

Den tar varje element i ett iterbart objekt, t.ex. en lista, tupel eller ett intervall, med ett godtyckligt variabelnamn och utvärderar det med ett uttryck. En ny lista med utvärderingsresultatet som element returneras.

Ett exempel ges tillsammans med ett motsvarande for-uttalande.

squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]
squares = []
for i in range(5):
    squares.append(i**2)

print(squares)
# [0, 1, 4, 9, 16]

Samma process kan göras med map(), men listförståelsen är att föredra på grund av sin enkelhet och tydlighet.

Notering av listförståelse med villkorlig förgrening genom om

Villkorlig förgrening med if är också möjlig. Skriv if i postfixet på följande sätt.

[Expression for Any Variable Name in Iterable Object if Conditional Expression]

Endast de element i det iterbara objektet vars villkorliga uttryck är sant utvärderas av uttrycket, och en ny lista vars element är resultatet returneras.

Du kan använda vilket variabelnamn som helst i det villkorliga uttrycket.

Ett exempel ges tillsammans med ett motsvarande for-uttalande.

odds = [i for i in range(10) if i % 2 == 1]
print(odds)
# [1, 3, 5, 7, 9]
odds = []
for i in range(10):
    if i % 2 == 1:
        odds.append(i)

print(odds)
# [1, 3, 5, 7, 9]

Samma process kan göras med filter(), men listförståelsen är att föredra på grund av sin enkelhet och tydlighet.

Kombination med ternära operatörer (behandling av typen ”om annars”)

I exemplet ovan behandlas endast de element som uppfyller kriterierna, och de som inte uppfyller kriterierna utesluts från den nya listan.

Om du vill byta process beroende på villkoret, eller om du vill behandla element som inte uppfyller villkoret på olika sätt, som i if else, använder du den ternära operatorn.

I Python kan den ternära operatören skrivas på följande sätt

Value When True if Conditional Expression else Value When False

Detta används i uttrycksdelen av listförståelsen som visas nedan.

[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]

Ett exempel ges tillsammans med ett motsvarande for-uttalande.

odd_even = ['odd' if i % 2 == 1 else 'even' for i in range(10)]
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
odd_even = []
for i in range(10):
    if i % 2 == 1:
        odd_even.append('odd')
    else:
        odd_even.append('even')

print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

Det är också möjligt att skriva uttryck med godtyckliga variabelnamn för de sanna och falska värdena.

Om villkoret är uppfyllt görs en viss bearbetning, annars lämnas värdet av det ursprungliga iterabla objektet oförändrat.

odd10 = [i * 10 if i % 2 == 1 else i for i in range(10)]
print(odd10)
# [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]

Kombination med zip() och enumerate()

Användbara funktioner som ofta används i for-anvisningen är zip(), som kombinerar flera iterables, och enumerate(), som returnerar ett värde tillsammans med dess index.

Det är naturligtvis möjligt att använda zip() och enumerate() med listförståelse. Det är ingen speciell syntax, och det är inte svårt om man tänker på korrespondensen med for-angivelsen.

Exempel på zip().

l_str1 = ['a', 'b', 'c']
l_str2 = ['x', 'y', 'z']

l_zip = [(s1, s2) for s1, s2 in zip(l_str1, l_str2)]
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
l_zip = []
for s1, s2 in zip(l_str1, l_str2):
    l_zip.append((s1, s2))

print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]

Exempel på enumerate().

l_enu = [(i, s) for i, s in enumerate(l_str1)]
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
l_enu = []
for i, s in enumerate(l_str1):
    l_enu.append((i, s))

print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]

Idén är densamma som tidigare när du använder if.

l_zip_if = [(s1, s2) for s1, s2 in zip(l_str1, l_str2) if s1 != 'b']
print(l_zip_if)
# [('a', 'x'), ('c', 'z')]

Varje element kan också användas för att beräkna ett nytt element.

l_int1 = [1, 2, 3]
l_int2 = [10, 20, 30]

l_sub = [i2 - i1 for i1, i2 in zip(l_int1, l_int2)]
print(l_sub)
# [9, 18, 27]

Notation för inklusion i en inbäddad lista.

Liksom nischade for-slingor kan listförståelse-notationen också nischas.

[Expression for Variable Name 1 in Iterable Object 1
    for Variable Name 2 in Iterable Object 2
        for Variable Name 3 in Iterable Object 3 ... ]

För enkelhetens skull har radbrytningar och indragningar lagts till, men de är inte nödvändiga för grammatiken; de kan fortsätta på en enda rad.

Ett exempel ges tillsammans med ett motsvarande for-uttalande.

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
flat = []
for row in matrix:
    for x in row:
        flat.append(x)

print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Det är också möjligt att använda flera variabler.

cells = [(row, col) for row in range(3) for col in range(2)]
print(cells)
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

Du kan också göra villkorlig förgrening.

cells = [(row, col) for row in range(3)
         for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]

Det är också möjligt att för varje iterabelt objekt göra en villkorlig förgrening.

cells = [(row, col) for row in range(3) if row % 2 == 0
         for col in range(2) if col % 2 == 0]
print(cells)
# [(0, 0), (2, 0)]

Notation för inklusion av uppsättningar.(Set comprehensions)

Om du byter ut hakparenteser [] i listförståelsen mot parenteser {} skapas en uppsättning (objekt av uppsättningstyp).

{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}

print(s)
# {0, 1, 4, 9, 16}

Notation för inklusion i ordboken.(Dict comprehensions)

Ordböcker (objekt av typen dict) kan också genereras med förståelse-notation.

{}, och ange nyckel och värde i uttrycksdelen som nyckel: värde.

{Key: Value for Any Variable Name in Iterable Object}

Alla uttryck kan anges för nyckel och värde.

l = ['Alice', 'Bob', 'Charlie']

d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}

Om du vill skapa en ny ordbok från en lista med nycklar och värden använder du funktionen zip().

keys = ['k1', 'k2', 'k3']
values = [1, 2, 3]

d = {k: v for k, v in zip(keys, values)}
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}

typ av generator(Generator expressions)

Om hakparenteser [] i listförståelsen används som runda parenteser () returneras en generator i stället för en tupel. Detta kallas generatoruttryck.

Exempel på en notation för listförståelse.

l = [i**2 for i in range(5)]

print(l)
# [0, 1, 4, 9, 16]

print(type(l))
# <class 'list'>

Exempel på ett generatoruttryck. Om du skriver ut() generatorn som den är kommer den inte att skriva ut innehållet, men om du kör den med en for-angivelse kan du få fram innehållet.

g = (i**2 for i in range(5))

print(g)
# <generator object <genexpr> at 0x10af944f8>

print(type(g))
# <class 'generator'>

for i in g:
    print(i)
# 0
# 1
# 4
# 9
# 16

Generatoruttryck tillåter också villkorlig förgrening och häckning med hjälp av om- och listförståelsenotation.

g_cells = ((row, col) for row in range(0, 3)
           for col in range(0, 2) if col == row)

print(type(g_cells))
# <class 'generator'>

for i in g_cells:
    print(i)
# (0, 0)
# (1, 1)

Om till exempel en lista med ett stort antal element genereras med hjälp av list comprehension notation och sedan loopas igenom med en for-angivelse, kommer listan med alla element att genereras i början om list comprehension notation används. Om du däremot använder ett generatoruttryck genereras elementen en efter en varje gång slingan upprepas, vilket minskar mängden minne som används.

Om generatoruttrycket är funktionens enda argument kan de runda parenteserna () utelämnas.

print(sum([i**2 for i in range(5)]))
# 30

print(sum((i**2 for i in range(5))))
# 30

print(sum(i**2 for i in range(5)))
# 30

När det gäller bearbetningshastighet är listförståelsen ofta snabbare än generatornotationen när alla element bearbetas.

Vid bedömning med all() eller any(), till exempel, bestäms dock resultatet när false eller true förekommer, så det kan vara snabbare att använda generatoruttryck än att använda listförståelse-notation.

Det finns ingen tupelförståelsenotation, men om du använder ett generatoruttryck som argument för tuple() kan du generera en tupel i förståelsenotationen.

t = tuple(i**2 for i in range(5))

print(t)
# (0, 1, 4, 9, 16)

print(type(t))
# <class 'tuple'>