Menggunakan notasi pemahaman senarai Python

Perniagaan

Dalam Python, mudah untuk menggunakan notasi pemahaman senarai apabila menjana senarai baharu.(List comprehensions)

Dalam artikel ini, kita akan membincangkan perkara berikut terlebih dahulu

  • Jenis asas tatatanda pemahaman senarai
  • Senaraikan tatatanda pemahaman dengan percabangan bersyarat dengan jika
  • Gabungan dengan pengendali ternary (jika pemprosesan seperti lain)
  • zip(),enumerate()Gabungan dengan ini
  • tatatanda kemasukan senarai bersarang

Seterusnya, kami akan menerangkan set tatatanda pemahaman senarai dengan kod sampel.

  • tetapkan tatatanda kemasukan(Set comprehensions)
  • notasi kemasukan kamus(Dict comprehensions)
  • jenis penjana(Generator expressions)

Jenis asas tatatanda pemahaman senarai

Notasi pemahaman senarai ditulis seperti berikut.

[Expression for Any Variable Name in Iterable Object]

Ia mengambil setiap elemen objek boleh lelar seperti senarai, tuple atau julat dengan nama pembolehubah arbitrari dan menilainya dengan ungkapan. Senarai baharu dengan hasil penilaian sebagai elemen dikembalikan.

Satu contoh diberikan bersama-sama dengan pernyataan yang setara.

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]

Proses yang sama boleh dilakukan dengan map(), tetapi notasi pemahaman senarai lebih disukai kerana kesederhanaan dan kejelasannya.

Senaraikan tatatanda pemahaman dengan percabangan bersyarat dengan jika

Cawangan bersyarat dengan jika juga boleh. Tulis jika dalam postfix seperti berikut.

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

Hanya unsur-unsur objek boleh lelar yang ungkapan bersyaratnya adalah benar dinilai oleh ungkapan, dan senarai baharu yang unsur-unsurnya adalah hasilnya dikembalikan.

Anda boleh menggunakan sebarang nama pembolehubah dalam ungkapan bersyarat.

Satu contoh diberikan bersama-sama dengan pernyataan yang setara.

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]

Proses yang sama boleh dilakukan dengan penapis(), tetapi notasi pemahaman senarai lebih disukai kerana kesederhanaan dan kejelasannya.

Gabungan dengan pengendali ternary (jika pemprosesan seperti lain)

Dalam contoh di atas, hanya elemen yang memenuhi kriteria diproses dan elemen yang tidak memenuhi kriteria dikecualikan daripada senarai baharu.

Jika anda ingin menukar proses bergantung pada keadaan, atau jika anda ingin memproses elemen yang tidak memenuhi syarat secara berbeza, seperti jika lain, gunakan operator ternary.

Dalam Python, pengendali ternary boleh ditulis seperti berikut

Value When True if Conditional Expression else Value When False

Ini digunakan dalam bahagian ungkapan notasi pemahaman senarai seperti yang ditunjukkan di bawah.

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

Satu contoh diberikan bersama-sama dengan pernyataan yang setara.

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

Ia juga mungkin untuk menulis ungkapan menggunakan nama pembolehubah arbitrari untuk nilai benar dan salah.

Jika syarat itu dipenuhi, beberapa pemprosesan dilakukan, jika tidak, nilai objek boleh lelar asal dibiarkan tidak berubah.

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]

Gabungan dengan zip() dan enumerate()

Fungsi berguna yang sering digunakan dalam pernyataan for termasuk zip(), yang menggabungkan berbilang iterable, dan enumerate(), yang mengembalikan nilai bersama indeksnya.

Sudah tentu, adalah mungkin untuk menggunakan zip() dan enumerate() dengan tatatanda pemahaman senarai. Ia bukan sintaks khas, dan ia tidak sukar jika anda mempertimbangkan surat-menyurat dengan pernyataan for.

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

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

Ideanya adalah sama seperti sebelum ini apabila menggunakan 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')]

Setiap elemen juga boleh digunakan untuk mengira elemen baharu.

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]

tatatanda kemasukan senarai bersarang

Seperti bersarang untuk gelung, tatatanda pemahaman senarai juga boleh disarangkan.

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

Untuk kemudahan, pemisah baris dan lekukan telah ditambahkan, tetapi tidak diperlukan untuk tatabahasa; mereka boleh diteruskan pada satu baris.

Satu contoh diberikan bersama-sama dengan pernyataan yang setara.

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]

Ia juga mungkin untuk menggunakan pelbagai pembolehubah.

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

Anda juga boleh melakukan percabangan bersyarat.

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

Ia juga mungkin untuk bercabang bersyarat untuk setiap objek boleh lelaran.

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

tetapkan tatatanda kemasukan(Set comprehensions)

Menukar kurungan segi empat sama [] dalam notasi pemahaman senarai kepada kurungan kerinting {} mencipta set (objek jenis set).

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

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

notasi kemasukan kamus(Dict comprehensions)

Kamus (objek jenis dict) juga boleh dijana dengan tatatanda pemahaman.

{}, dan tentukan kunci dan nilai dalam bahagian ungkapan sebagai kunci: nilai.

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

Sebarang ungkapan boleh ditentukan untuk kunci dan nilai.

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

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

Untuk mencipta kamus baharu daripada senarai kunci dan nilai, gunakan fungsi 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}

jenis penjana(Generator expressions)

Jika kurungan segi empat sama [] dalam notasi pemahaman senarai digunakan sebagai kurungan bulat (), penjana dikembalikan dan bukannya tupel. Ini dipanggil ungkapan penjana.

Contoh tatatanda pemahaman senarai.

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

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

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

Contoh ungkapan penjana. Jika anda mencetak() penjana sebagaimana adanya, ia tidak akan mencetak kandungannya, tetapi jika anda menjalankannya dengan pernyataan for, anda boleh mendapatkan kandungannya.

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

Ungkapan penjana juga membenarkan percabangan dan sarang bersyarat menggunakan if serta tatatanda pemahaman senarai.

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)

Sebagai contoh, jika senarai dengan bilangan elemen yang banyak dijana menggunakan tatatanda pemahaman senarai dan kemudian dilingkarkan dengan pernyataan for, senarai yang mengandungi semua elemen akan dijana pada permulaan jika tatatanda pemahaman senarai digunakan. Sebaliknya, jika anda menggunakan ungkapan penjana, setiap kali gelung diulang, elemen dijana satu demi satu, sekali gus mengurangkan jumlah memori yang digunakan.

Jika ungkapan penjana adalah satu-satunya hujah bagi fungsi tersebut, kurungan bulat () boleh diabaikan.

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

Bagi kelajuan pemprosesan, notasi pemahaman senarai selalunya lebih cepat daripada notasi penjana apabila semua elemen diproses.

Walau bagaimanapun, apabila menilai dengan all() atau any(), sebagai contoh, keputusan ditentukan apabila palsu atau benar hadir, jadi menggunakan ungkapan penjana mungkin lebih pantas daripada menggunakan tatatanda pemahaman senarai.

Tiada notasi pemahaman tuple, tetapi jika anda menggunakan ungkapan penjana sebagai hujah bagi tuple(), anda boleh menjana satu tuple dalam notasi pemahaman.

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

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

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