Utilizarea notației Python list comprehensions

Afaceri

În Python, este simplu să folosiți notația de înțelegere a listelor atunci când generați o nouă listă.(List comprehensions)

În acest articol, vom discuta mai întâi următoarele aspecte

  • Tipul de bază al notației de înțelegere a listelor
  • Notația de înțelegere a listei cu ramificare condiționată prin if
  • Combinație cu operatori ternari (procesare de tip if else)
  • zip(),enumerate()Combinație cu acestea
  • notația de includere a listei imbricate

În continuare, vom explica setul de notații de înțelegere a listei cu ajutorul unui exemplu de cod.

  • notația de includere a setului(Set comprehensions)
  • notația de includere în dicționar(Dict comprehensions)
  • tip de generator(Generator expressions)

Tipul de bază al notației de înțelegere a listelor

Notația de înțelegere a listei se scrie după cum urmează.

[Expression for Any Variable Name in Iterable Object]

Acesta ia fiecare element al unui obiect iterabil, cum ar fi o listă, un tuplu sau un interval, printr-un nume de variabilă arbitrar și îl evaluează cu o expresie. Se returnează o nouă listă cu rezultatul evaluării ca element.

Se oferă un exemplu, împreună cu o declarație for echivalentă.

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]

Același proces poate fi realizat și cu map(), dar notația de înțelegere a listei este preferată pentru simplitatea și claritatea sa.

Notația de înțelegere a listei cu ramificare condiționată prin if

De asemenea, este posibilă branșarea condiționată cu if. Scrieți if în postfix după cum urmează.

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

Numai elementele obiectului iterabil a căror expresie condițională este adevărată sunt evaluate de expresie și se returnează o nouă listă ale cărei elemente sunt rezultatul.

Puteți utiliza orice nume de variabilă în expresia condiționată.

Se oferă un exemplu, împreună cu o declarație for echivalentă.

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]

Același proces poate fi realizat cu filter(), dar notația de înțelegere a listei este preferată pentru simplitatea și claritatea sa.

Combinație cu operatori ternari (procesare de tip if else)

În exemplul de mai sus, sunt procesate numai elementele care îndeplinesc criteriile, iar cele care nu îndeplinesc criteriile sunt excluse din noua listă.

Dacă doriți să comutați procesul în funcție de condiție sau dacă doriți să procesați în mod diferit elementele care nu îndeplinesc condiția, ca în if else, utilizați operatorul ternar.

În Python, operatorul ternar poate fi scris după cum urmează

Value When True if Conditional Expression else Value When False

Aceasta este utilizată în partea de expresie a notației de înțelegere a listei, după cum se arată mai jos.

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

Se oferă un exemplu, împreună cu o declarație for echivalentă.

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

De asemenea, este posibil să se scrie expresii folosind nume arbitrare de variabile pentru valorile adevărate și false.

În cazul în care condiția este îndeplinită, se efectuează o anumită procesare; în caz contrar, valoarea obiectului iterabil original rămâne neschimbată.

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]

Combinație cu zip() și enumerate()

Printre funcțiile utile care sunt adesea utilizate în instrucțiunea for se numără zip(), care combină mai multe iterabile, și enumerate(), care returnează o valoare împreună cu indicele acesteia.

Bineînțeles, este posibil să se utilizeze zip() și enumerate() cu notația de înțelegere a listei. Nu este o sintaxă specială și nu este dificil dacă luați în considerare corespondența cu instrucțiunea for.

Exemplu de 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')]

Exemplu de 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')]

Ideea este aceeași ca și înainte, atunci când se utilizează 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')]

Fiecare element poate fi, de asemenea, utilizat pentru a calcula un nou 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]

notația de includere a listei imbricate

La fel ca în cazul buclelor de tip „for”, notația de înțelegere a listelor poate fi, de asemenea, imbricata.

[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 ... ]

Pentru comoditate, au fost adăugate pauze de linie și indentări, dar nu sunt necesare pentru gramatică; acestea pot fi continuate pe o singură linie.

Se oferă un exemplu, împreună cu o declarație for echivalentă.

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]

De asemenea, este posibil să se utilizeze mai multe variabile.

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

De asemenea, puteți face o ramificare condiționată.

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

De asemenea, este posibil să se facă o ramificare condiționată pentru fiecare obiect iterabil.

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

notația de includere a setului(Set comprehensions)

Schimbarea parantezelor pătrate [] din notația de înțelegere a listei în paranteze drepte {} creează un set (obiect de tip set).

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

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

notația de includere în dicționar(Dict comprehensions)

Dicționarele (obiecte de tip dict) pot fi, de asemenea, generate cu notația de înțelegere.

{} și specificați cheia și valoarea în partea de expresie ca cheie: valoare.

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

Se poate specifica orice expresie pentru cheie și valoare.

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

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

Pentru a crea un nou dicționar dintr-o listă de chei și valori, utilizați funcția 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}

tip de generator(Generator expressions)

În cazul în care parantezele pătrate [] din notația de înțelegere a listelor sunt utilizate ca paranteze rotunde (), se returnează un generator în loc de un tupluplu. Aceasta se numește expresii generatoare.

Exemplu de notație de înțelegere a listei.

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

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

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

Exemplu de expresie generatoare. Dacă imprimați () generatorul așa cum este, nu va imprima conținutul său, dar dacă îl rulați cu o instrucțiune for, puteți obține conținutul.

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

Expresiile generatoare permit, de asemenea, bifurcații condiționate și anidarea folosind notația if, precum și notația de înțelegere a listei.

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)

De exemplu, dacă o listă cu un număr mare de elemente este generată utilizând notația de înțelegere a listei și apoi parcursă în buclă cu o instrucțiune for, lista care conține toate elementele va fi generată la început dacă se utilizează notația de înțelegere a listei. Pe de altă parte, dacă se utilizează o expresie generatoare, de fiecare dată când se repetă bucla, elementele sunt generate unul câte unul, reducându-se astfel cantitatea de memorie utilizată.

În cazul în care expresia generatorului este singurul argument al funcției, parantezele rotunde () pot fi omise.

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 ceea ce privește viteza de procesare, notația de înțelegere a listei este adesea mai rapidă decât notația generatorului atunci când sunt procesate toate elementele.

Cu toate acestea, atunci când judecați cu all() sau any(), de exemplu, rezultatul este determinat atunci când este prezent fals sau adevărat, astfel încât utilizarea expresiilor generatoare poate fi mai rapidă decât utilizarea notației de înțelegere a listei.

Nu există o notație de înțelegere a tuplelor, dar dacă utilizați o expresie generatoare ca argument pentru tuple(), puteți genera un tuplu în notația de înțelegere.

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

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

print(type(t))
# <class 'tuple'>
Copied title and URL