Python 목록 이해 표기법 사용

사업

Python에서 새 목록을 생성할 때 목록 이해 표기법을 사용하는 것은 간단합니다.(List comprehensions)

이 기사에서 우리는 먼저 다음을 논의 할 것입니다

  • 목록 이해 표기법의 기본 유형
  • if에 의한 조건부 분기가 있는 목록 이해 표기법
  • 삼항 연산자와의 조합(else-like 처리인 경우)
  • zip(),enumerate()이들과의 조합
  • 중첩 목록 포함 표기법

다음으로 샘플 코드를 사용하여 목록 이해 표기법 집합에 대해 설명합니다.

  • 포함 표기법 설정(Set comprehensions)
  • 사전 포함 표기법(Dict comprehensions)
  • 발전기 유형(Generator expressions)

목록 이해 표기법의 기본 유형

목록 이해 표기법은 다음과 같이 작성됩니다.

[Expression for Any Variable Name in Iterable Object]

목록, 튜플 또는 범위와 같은 반복 가능한 개체의 각 요소를 임의의 변수 이름으로 가져와 표현식으로 평가합니다. 평가 결과가 요소로 포함된 새 목록이 반환됩니다.

동일한 for 문과 함께 예제가 제공됩니다.

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]

map()을 사용하여 동일한 프로세스를 수행할 수 있지만 단순성과 명확성을 위해 목록 이해 표기법이 선호됩니다.

if에 의한 조건부 분기가 있는 목록 이해 표기법

if로 조건부 분기도 가능합니다. 다음과 같이 접미사에 if를 쓰십시오.

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

조건식이 true인 iterable 객체의 요소만 표현식에 의해 평가되고 요소가 결과인 새 목록이 반환됩니다.

조건식에는 모든 변수 이름을 사용할 수 있습니다.

동일한 for 문과 함께 예제가 제공됩니다.

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]

동일한 프로세스를 filter()로 수행할 수 있지만 단순성과 명확성을 위해 목록 이해 표기법이 선호됩니다.

삼항 연산자와의 조합(else-like 처리인 경우)

위의 예에서는 기준에 맞는 요소만 처리하고 기준에 맞지 않는 요소는 새 목록에서 제외합니다.

조건에 따라 프로세스를 전환하거나 if else와 같이 조건을 충족하지 않는 요소를 다르게 처리하려면 삼항 연산자를 사용합니다.

Python에서 삼항 연산자는 다음과 같이 작성할 수 있습니다.

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]

동일한 for 문과 함께 예제가 제공됩니다.

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

true 및 false 값에 대해 임의의 변수 이름을 사용하여 표현식을 작성할 수도 있습니다.

조건이 충족되면 일부 처리가 완료되고, 그렇지 않으면 원래 반복 가능한 객체의 값이 변경되지 않은 상태로 남습니다.

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]

zip() 및 enumerate()와의 조합

for 문에서 자주 사용되는 유용한 함수로는 여러 iterable을 결합하는 zip()과 인덱스와 함께 값을 반환하는 enumerate()가 있습니다.

물론 목록 이해 표기법과 함께 zip() 및 enumerate()를 사용할 수 있습니다. 특별한 문법도 아니고 for문과의 대응을 생각해보면 어렵지 않습니다.

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

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

아이디어는 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')]

각 요소를 사용하여 새 요소를 계산할 수도 있습니다.

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

편의를 위해 줄 바꿈과 들여쓰기가 추가되었지만 문법에는 필요하지 않습니다. 한 줄에서 계속할 수 있습니다.

동일한 for 문과 함께 예제가 제공됩니다.

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)

사전(dict 유형 객체)도 이해 표기법으로 생성할 수 있습니다.

{}를 사용하고 표현식 부분의 키와 값을 key:value로 지정합니다.

{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}

키와 값 목록에서 새 사전을 만들려면 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}

발전기 유형(Generator expressions)

목록 내포 표기법에서 대괄호 []를 대괄호()로 사용하면 튜플 대신 제너레이터가 반환됩니다. 이것을 제너레이터 표현식이라고 합니다.

목록 이해 표기법의 예.

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

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

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

생성기 표현식의 예. 제너레이터를 그대로 print()하면 내용을 출력하지 않지만 for문으로 실행하면 내용을 얻을 수 있다.

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

생성기 표현식은 목록 이해 표기법뿐만 아니라 if를 사용하여 조건부 분기 및 중첩도 허용합니다.

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)

예를 들어, 목록 이해 표기법을 사용하여 많은 수의 요소가 있는 목록을 생성한 다음 for 문으로 반복하는 경우 목록 이해 표기법을 사용하면 모든 요소를 ​​포함하는 목록이 처음에 생성됩니다. 반면에 제너레이터 표현식을 사용하면 루프가 반복될 때마다 요소가 하나씩 생성되기 때문에 메모리 사용량이 줄어듭니다.

생성기 표현식이 함수의 유일한 인수인 경우 대괄호()를 생략할 수 있습니다.

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

처리 속도에 관해서는 모든 요소가 처리될 때 목록 이해 표기법이 생성기 표기법보다 빠른 경우가 많습니다.

그러나 예를 들어 all() 또는 any()로 판단할 때 결과는 false 또는 true가 있을 때 결정되므로 목록 이해 표기법을 사용하는 것보다 제너레이터 표현식을 사용하는 것이 더 빠를 수 있습니다.

튜플 이해 표기법은 없지만 tuple()의 인수로 제너레이터 표현식을 사용하면 이해 표기법으로 튜플을 생성할 수 있다.

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

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

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