У Питхон-у је једноставно користити нотацију разумевања листе када се генерише нова листа.(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
У овом чланку прво ћемо разговарати о следећем
- Основни тип нотације за разумевање листе
- Запис за разумевање листе са условним гранањем ако
- Комбинација са тернарним операторима (ако је другачија обрада)
zip()
,enumerate()
Комбинација са овим- нотација укључивања угнежђене листе
Затим ћемо објаснити скуп нотације за разумевање листе са примером кода.
- сет инклузивне нотације(
Set comprehensions
) - речник инклузија нотација(
Dict comprehensions
) - тип генератора(
Generator expressions
)
- Основни тип нотације за разумевање листе
- Запис за разумевање листе са условним гранањем ако
- Комбинација са тернарним операторима (ако је другачија обрада)
- Комбинација са зип() и енумерате()
- нотација укључивања угнежђене листе
- сет инклузивне нотације(Set comprehensions)
- речник инклузија нотација(Dict comprehensions)
- тип генератора(Generator expressions)
Основни тип нотације за разумевање листе
Нотација за разумевање листе је написана на следећи начин.
[Expression for Any Variable Name in Iterable Object]
Узима сваки елемент итеративног објекта као што је листа, тупле или опсег помоћу произвољног имена променљиве и процењује га помоћу израза. Враћа се нова листа са резултатом евалуације као елементом.
Пример је дат заједно са еквивалентом за исказ.
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]
Исти процес се може урадити са мапом(), али је нотација за разумевање листе пожељнија због своје једноставности и јасноће.
Запис за разумевање листе са условним гранањем ако
Могуће је и условно гранање са иф. Напишите иф у постфиксу на следећи начин.
[Expression for Any Variable Name in Iterable Object if Conditional Expression]
Изразом се вреднују само елементи итеративног објекта чији је условни израз истинит, а враћа се нова листа чији су елементи резултат.
Можете користити било које име променљиве у условном изразу.
Пример је дат заједно са еквивалентом за исказ.
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]
Исти процес се може урадити са филтер(), али је нотација за разумевање листе пожељнија због своје једноставности и јасноће.
Комбинација са тернарним операторима (ако је другачија обрада)
У горњем примеру обрађују се само они елементи који испуњавају критеријуме, а они који не испуњавају критеријуме се искључују из нове листе.
Ако желите да промените процес у зависности од услова, или ако желите да обрадите елементе који не задовољавају услов другачије, као у иф елсе, користите тернарни оператор.
У Питхон-у, тернарни оператор се може написати на следећи начин
Value When True if Conditional Expression else Value When False
Ово се користи у делу израза у нотацији разумевања листе као што је приказано испод.
[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]
Пример је дат заједно са еквивалентом за исказ.
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']
Такође је могуће писати изразе користећи произвољна имена променљивих за тачне и нетачне вредности.
Ако је услов задовољен, нека обрада се врши, у супротном вредност оригиналног итерабле објекта остаје непромењена.
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]
Комбинација са зип() и енумерате()
Корисне функције које се често користе у наредби фор укључују зип(), који комбинује вишеструке итерабле, и енумерате(), који враћа вредност заједно са својим индексом.
Наравно, могуће је користити зип() и енумерате() са нотацијом за разумевање листе. То није посебна синтакса и није тешко ако узмете у обзир кореспонденцију са наредбом фор.
Пример зип().
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')]
Пример енумерате().
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')]
Идеја је иста као и раније када се користи иф.
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')]
Сваки елемент се такође може користити за израчунавање новог елемента.
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]
нотација укључивања угнежђене листе
Попут гнежђења за петље, нотација разумевања листе такође може бити угнежђена.
[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 ... ]
Ради погодности, додани су преломи редова и увлачења, али нису потребни за граматику; могу се наставити на једном реду.
Пример је дат заједно са еквивалентом за исказ.
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]
Такође је могуће користити више променљивих.
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)]
Такође можете извршити условно гранање.
cells = [(row, col) for row in range(3)
for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]
Такође је могуће условно гранати за сваки итерабле објекат.
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)]
сет инклузивне нотације(Set comprehensions)
Промена угластих заграда [] у нотацији разумевања листе у витичасте заграде {} ствара скуп (објекат типа скупа).
{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}
print(s)
# {0, 1, 4, 9, 16}
речник инклузија нотација(Dict comprehensions)
Речници (објекти типа дицт) се такође могу генерисати са нотацијом разумевања.
{} и наведите кључ и вредност у делу израза као кључ: вредност.
{Key: Value for Any Variable Name in Iterable Object}
За кључ и вредност може се навести било који израз.
l = ['Alice', 'Bob', 'Charlie']
d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}
Да бисте креирали нови речник са листе кључева и вредности, користите функцију зип().
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}
тип генератора(Generator expressions)
Ако се угласте заграде [] у нотацији разумевања листе користе као округле заграде (), враћа се генератор уместо торке. Ово се зове генераторски изрази.
Пример нотације за разумевање листе.
l = [i**2 for i in range(5)]
print(l)
# [0, 1, 4, 9, 16]
print(type(l))
# <class 'list'>
Пример израза генератора. Ако штампате() генератор какав јесте, он неће одштампати његов садржај, али ако га покренете са фор наредбом, можете добити садржај.
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
Изрази генератора такође дозвољавају условно гранање и угнежђење коришћењем ако, као и нотације за разумевање листе.
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)
На пример, ако се листа са великим бројем елемената генерише коришћењем нотације разумевања листе, а затим прође кроз петљу са фор наредбом, листа која садржи све елементе биће генерисана на почетку ако се користи нотација за разумевање листе. С друге стране, ако користите израз генератора, сваки пут када се петља понавља, елементи се генеришу један по један, чиме се смањује количина коришћене меморије.
Ако је израз генератора једини аргумент функције, округле заграде () се могу изоставити.
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
Што се тиче брзине обраде, нотација разумевања листе је често бржа од нотације генератора када се обрађују сви елементи.
Међутим, када се суди са алл() или ани(), на пример, резултат се утврђује када је присутан фалсе или труе, тако да коришћење израза генератора може бити брже од коришћења нотације за разумевање листе.
Не постоји нотација разумевања тупле, али ако користите израз генератора као аргумент тупле(), можете генерисати тупле у нотацији разумевања.
t = tuple(i**2 for i in range(5))
print(t)
# (0, 1, 4, 9, 16)
print(type(t))
# <class 'tuple'>