python for문 사용과 list comprehension


python에서 for문과 자주 비교되서 사용되는 list comprehension 구조를 위한 포스팅입니다.

보통 루프문을 일반적으로 배울 때는 for, while문을 먼저 배운다.

그러면 이러한 루프문에서 나온 값을 바로 적용하기 위해서는

보통은 리스트를 미리 만들고 append를 하도록 배우는 것이 보편적이다.

하지만 이러한 방법은 미리 할당도 하여야되고 수가 기하급수적으로 많아지면 루프문이 매우 느리게 실행 되는 것을 볼 수 있다.

이러한 상황을 해결하기 위해서 그 다음으로 배우는 것이 바로 list comprehension이다.

일단 특정 패키지 없이 사용이 가능하다는 점에서 좋고 짧은 구조에서는 가독성도 나쁘지 않은 편이다.

속도의 경우는 생략하고 바로 사용 방법만 다뤄보기로 하겠다

바로 예시를 통해서 비교를 해보도록 하자.

첫 번째로는 숫자 리스트의 숫자를 문자로만 바꿔서 문자 리스트로 바꾸는 작업이다

In [1]:
# list comprehension

name = [123, 456, 789, 101112]

list1 = []
for first in name:
    list1.append( str(first) )

list1    
Out[1]:
['123', '456', '789', '101112']

일반 for문을 쓰면 보통은 빈 리스트를 만들고 이를 append하는 방식이지만

In [2]:
[str(first) for first in name]
Out[2]:
['123', '456', '789', '101112']

list comprehension은 그냥 리스트안에 for문을 집어넣어서 리스트 안에서 해당 방식이 실행이 되도록 하여서

집어넣는 과정을 생략하여서 속도가 훨씬 빠르게 된다.

이 방법을 보면 두 가지 생각이 들 것이다.

첫 번째는 도대체 뭔 구조로 이루어 진 것이고

두 번째는 이중 for 문으로 안되는거면 복잡한 경우에는 for문으로만 해야되는거네 라는 것이다.

첫 번째를 자세히 설명하자면

for first in name에서 name은 전체 항목이고 first에는 각 항목이 나와서 이를 전체적으로 실행하는 방식이다.

[str(first) for first in name] 에서 뒷 부분은 일반 for문과 동일한 것이다.

그렇다면 맨 앞의 str(first)는 무엇이냐면 for문에서 : 뒤에 나오는 것이다.

list comprehension은 실제 실행이 되어야되는 내용을 맨 앞에 두고 for문을 뒤에 두는 방식이다.

두 번째의 경우는 바로 다음 예시를 보도록 하겠다.

In [3]:
name2 = ['123', '456', '789', '101112']

list2 = []
for first in name2:
    for second in first:
        list2.append( str(second) )
        
list2
Out[3]:
['1', '2', '3', '4', '5', '6', '7', '8', '9', '1', '0', '1', '1', '1', '2']

list comprehension에서도 이중 for문이 실행이 가능한데

바로 첫 번째로 실행이 되는 for문 다음에 이중 for문으로 또 들어가는 항목을 넣고

최종적으로 실제 실행이 되어야 되는 내용을 맨 앞에 놔두는 것이다.

In [4]:
name3 = [ ['123', '456', '789', '101112'], ['123', '456'] ]

list3 = []
for first in name3:
    for second in first:
        for third in second:
            list3.append( str(third) )
        
print( list3 )

print( [str(third) for first in name3 for second in first for third in second] )
['1', '2', '3', '4', '5', '6', '7', '8', '9', '1', '0', '1', '1', '1', '2', '1', '2', '3', '4', '5', '6']
['1', '2', '3', '4', '5', '6', '7', '8', '9', '1', '0', '1', '1', '1', '2', '1', '2', '3', '4', '5', '6']
In [5]:
[str(third) for first in name3 for second in first for third in second]
Out[5]:
['1',
 '2',
 '3',
 '4',
 '5',
 '6',
 '7',
 '8',
 '9',
 '1',
 '0',
 '1',
 '1',
 '1',
 '2',
 '1',
 '2',
 '3',
 '4',
 '5',
 '6']

삼중으로 실행 시키는 경우도 비슷하게 하면 된다.

단 중간에 실제 실행하는 내용이 들어가는 경우, 경우에 따라 이중 for문으로만 해도 되는 경우가

3중 list comprehension으로 구성하여야되는 경우도 있다.

In [6]:
list2 = []
for first in name2:
    first = first + 'a'
    for second in first:
        list2.append( str(second) )
        
list2
Out[6]:
['1',
 '2',
 '3',
 'a',
 '4',
 '5',
 '6',
 'a',
 '7',
 '8',
 '9',
 'a',
 '1',
 '0',
 '1',
 '1',
 '1',
 '2',
 'a']
In [7]:
[str(third) for second in [first + 'a' for first in name2 ] for third in second ]
Out[7]:
['1',
 '2',
 '3',
 'a',
 '4',
 '5',
 '6',
 'a',
 '7',
 '8',
 '9',
 'a',
 '1',
 '0',
 '1',
 '1',
 '1',
 '2',
 'a']

list comprehension은 짧은 구조에 간단히 사용하면 좋지만,

23중으로 가는 경우와 복잡한 경우 그리고 특히 다른 사람이 코드를 보고 나중에 수정을 할 필요가 있는 내용이라면

이러한 방식으로 구현을 절대 하지 않는 것을 권한다.

가장 큰 이유는 가독성이 떨어지며, 코드 특성 상 몇 달만 지나도 본인조차 까먹기 때문에

코드를 해석하기 위해서라면 알아두면 좋지만, 굳이 권장은 하지 않는다.

함수에 넣어서 자주 사용을 할거라면 덕 타이핑으로 해당 설명을 필수적으로 넣어줘야된다고 본다.