A Python, és senzill utilitzar la notació de comprensió de llista quan es genera una llista nova.(List comprehensions
)
- 5. Data Structures — List Comprehensions — Python 3.10.0 Documentation
- 6. Expressions — Displays for lists, sets and dictionaries — Python 3.10.0 Documentation
En aquest article, primer parlarem del següent
- Tipus bàsic de notació de comprensió de llista
- Llista la notació de comprensió amb ramificació condicional per if
- Combinació amb operadors ternaris (si el processament és similar)
zip()
,enumerate()
Combinació amb aquests- notació d’inclusió de llista imbricada
A continuació, explicarem el conjunt de notació de comprensió de llistes amb codi d’exemple.
- establir la notació d’inclusió(
Set comprehensions
) - notació d’inclusió del diccionari(
Dict comprehensions
) - tipus de generador(
Generator expressions
)
- Tipus bàsic de notació de comprensió de llista
- Llista la notació de comprensió amb ramificació condicional per if
- Combinació amb operadors ternaris (si el processament és similar)
- Combinació amb zip() i enumerate()
- notació d’inclusió de llista imbricada
- establir la notació d’inclusió(Set comprehensions)
- notació d’inclusió del diccionari(Dict comprehensions)
- tipus de generador(Generator expressions)
Tipus bàsic de notació de comprensió de llista
La notació de comprensió de la llista s’escriu de la següent manera.
[Expression for Any Variable Name in Iterable Object]
Pren cada element d’un objecte iterable com una llista, una tupla o un rang per un nom de variable arbitrari i l’avalua amb una expressió. Es retorna una llista nova amb el resultat de l’avaluació com a element.
Es dóna un exemple juntament amb un equivalent per a l’enunciat.
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]
El mateix procés es pot fer amb map(), però es prefereix la notació de comprensió de llista per la seva senzillesa i claredat.
Llista la notació de comprensió amb ramificació condicional per if
La ramificació condicional amb if també és possible. Escriu el si al postfix de la manera següent.
[Expression for Any Variable Name in Iterable Object if Conditional Expression]
L’expressió només avalua els elements de l’objecte iterable l’expressió condicional del qual és certa i es retorna una llista nova els elements de la qual són el resultat.
Podeu utilitzar qualsevol nom de variable a l’expressió condicional.
Es dóna un exemple juntament amb un equivalent per a l’enunciat.
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]
El mateix procés es pot fer amb filter(), però es prefereix la notació de comprensió de llista per la seva senzillesa i claredat.
Combinació amb operadors ternaris (si el processament és similar)
A l’exemple anterior, només es processen aquells elements que compleixen els criteris i els que no compleixen els criteris queden exclosos de la llista nova.
Si voleu canviar el procés en funció de la condició, o si voleu processar elements que no compleixen la condició de manera diferent, com en cas contrari, utilitzeu l’operador ternari.
A Python, l’operador ternari es pot escriure de la següent manera
Value When True if Conditional Expression else Value When False
S’utilitza a la part d’expressió de la notació de comprensió de la llista tal com es mostra a continuació.
[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]
Es dóna un exemple juntament amb un equivalent per a l’enunciat.
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']
També és possible escriure expressions utilitzant noms de variable arbitraris per als valors vertader i fals.
Si es compleix la condició, es fa algun processament, en cas contrari, el valor de l’objecte iterable original no es modifica.
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]
Combinació amb zip() i enumerate()
Les funcions útils que s’utilitzen sovint a la instrucció for inclouen zip(), que combina múltiples iterables, i enumerate(), que retorna un valor juntament amb el seu índex.
Per descomptat, és possible utilitzar zip() i enumerate() amb notació de comprensió de llista. No és una sintaxi especial, i no és difícil si teniu en compte la correspondència amb la sentència for.
Exemple 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')]
Exemple 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')]
La idea és la mateixa que abans quan s’utilitza 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')]
Cada element també es pot utilitzar per calcular un element nou.
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]
notació d’inclusió de llista imbricada
Igual que la nidificació de bucles, la notació de comprensió de llistes també es pot anidar.
[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 ... ]
Per comoditat, s’han afegit salts de línia i sagnats, però no són necessaris per a la gramàtica; es poden continuar en una sola línia.
Es dóna un exemple juntament amb un equivalent per a l’enunciat.
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]
També és possible utilitzar diverses variables.
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)]
També podeu fer ramificacions condicionals.
cells = [(row, col) for row in range(3)
for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]
També és possible ramificar condicionalment per a cada objecte iterable.
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)]
establir la notació d’inclusió(Set comprehensions)
Si canvieu els claudàtors [] a la notació de comprensió de la llista per claudàtors {}, es crea un conjunt (objecte de tipus conjunt).
{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}
print(s)
# {0, 1, 4, 9, 16}
notació d’inclusió del diccionari(Dict comprehensions)
Els diccionaris (objectes de tipus dict) també es poden generar amb notació de comprensió.
{}, i especifiqueu la clau i el valor a la part d’expressió com a clau: valor.
{Key: Value for Any Variable Name in Iterable Object}
Es pot especificar qualsevol expressió per a clau i valor.
l = ['Alice', 'Bob', 'Charlie']
d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}
Per crear un diccionari nou a partir d’una llista de claus i valors, utilitzeu la funció 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}
tipus de generador(Generator expressions)
Si els claudàtors [] a la notació de comprensió de la llista s’utilitzen com a claudàtors rodons (), es retorna un generador en lloc d’una tupla. Això s’anomena expressions generadores.
Exemple de notació de comprensió de llista.
l = [i**2 for i in range(5)]
print(l)
# [0, 1, 4, 9, 16]
print(type(l))
# <class 'list'>
Exemple d’expressió generadora. Si imprimiu () el generador tal com és, no imprimirà el seu contingut, però si l’executeu amb una instrucció for, podeu obtenir-ne el contingut.
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
Les expressions generadores també permeten ramificacions i nidificacions condicionals utilitzant if i la notació de comprensió de llista.
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)
Per exemple, si es genera una llista amb un gran nombre d’elements utilitzant la notació de comprensió de llista i després es fa un bucle amb una instrucció for, la llista que conté tots els elements es generarà al principi si s’utilitza la notació de comprensió de llista. D’altra banda, si utilitzeu una expressió generadora, cada vegada que es repeteix el bucle, els elements es generen un a un, reduint així la quantitat de memòria utilitzada.
Si l’expressió del generador és l’únic argument de la funció, els claudàtors () es poden ometre.
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
Pel que fa a la velocitat de processament, la notació de comprensió de la llista sovint és més ràpida que la notació del generador quan es processen tots els elements.
Tanmateix, quan es jutja amb all() o any(), per exemple, el resultat es determina quan hi ha fals o cert, de manera que l’ús d’expressions generadores pot ser més ràpid que l’ús de la notació de comprensió de llista.
No hi ha una notació de comprensió de tupla, però si utilitzeu una expressió generadora com a argument de tuple(), podeu generar una tupla a la notació de comprensió.
t = tuple(i**2 for i in range(5))
print(t)
# (0, 1, 4, 9, 16)
print(type(t))
# <class 'tuple'>