list comprehension
이란 새로운 리스트를 만들 때 사용할 수 있는 간단한 표현식으로 리스트와 마찬가지로 대괄호[]
를 사용하여 작성한다. 그리고 만들려고 하는 원소를 표현하는 표현식으로 시작하여 for loop
가 뒤에 따라오는 형식을 갖는다. For ~ if ~
로 조건문을 포함한 형식도 올 수 있다.
다음의 예시로 좀 더 이해해보자.
new_list = [ x for x in range(1,11) ]
print(new_list)
위와 같이 list의 요소를 직접 입력해주지 않아도 쉽게 list를 만들 수 있다.
if
문을 포함한 예시도 살펴보자.
odd_numbers = [ ]
for element in range(1,11):
if (element % 2) == 1:
odd_numbers.append(element)
print(odd_numbers)
위의 코드는 1~10까지를 element가 indexing하고 조건문을 사용해서 indexing한 element가 2로 나누었을 때, 나머지가 1이면, odd_numbers라는 list에 append하는 기능을 한다.
if문을 포함한 list_comprehension으로 상단의 코드를 다음과 같이 훨씬 간단하게 구현할 수 있다.
list_comprehension = [ element for element in range(1,11) if (element % 2) == 1 ]
print(list_comprehension)
같은 결과이지만 코드가 한줄로 훨씬 간결해졌다. 이와 같이 For loop 내부에서 새로운 리스트를 만드는 For loop는 list comprehension으로 변환할 수 있고, 반대로 list comprehension을 for loop로 변환할 수 있다.
list comprehension을 사용하여 코드를 작성하는것이 list comprehension을 사용하지 않은 코드에 비해서 성능이 얼마나 뛰어난지 확인해보자.
(개발자는 새로운 지식에 대해 습득할 때 '그렇구나' 하고 넘어가는 것보단 직접 코드도 작성해보고 코드를 실행도 시켜보고 하는 습관이 중요한 것 같다.)
다음의 코드는 timeit
모듈을 사용하여 함수들을 1000번 실행한 시간을 측정하는 코드다. 이 코드를 사용하여 for loop
코드 vs list comprehension
코드의 동작시간을 측정하여 비교해보자.
import timeit
def for_loop():
num_list = []
for i in range(1000):
num_list.append(i)
def list_comprehension():
num_list = [ i for i in range(1000) ]
if __name__ == "__main__":
time1 = timeit.Timer("for_loop()", "from __main__ import for_loop")
print("for loop time = ", time1.timeit(number=1000), "milliseconds")
time2 = timeit.Timer("list_comprehension()", "from __main__ import list_comprehension")
print("list_comprehension time = ", time2.timeit(number=1000), "milliseconds")
위와 같이 for loop
를 사용한 코드는 0.061ms, list comprehension
을 사용한 코드는 0.027ms로 더 빠르게 실행되는 것을 확인할 수 있다. 위 코드의 내용으로는 사람이 느낄정도의 성능 차이는 아니지만 코드가 복잡해지고 많은 내용을 다루는 프로그램에서 또는 0.01s처럼 아주 짧은 순간 순간이 굉장히 중요한 프로그램에서는 큰 성능 차이를 나타낼 것이다.
그리고 list comprehension
으로 작성한 코드는 간결하고 데이터베이스를 조회하여 list로 만들 때 많이 사용되므로 list comprehension
은 새로운 배열을 만들 때 특히 유용하다.
이렇게 성능 부분에서 좋은것은 맞지만 항상 모든 상황에서 list comprehension
의 작성이 권고되지는 않는다. 예를 들어 list comprehension
으로 작성된 복잡한 이중 for문의 코드는 한눈에 읽히지 않는다. 이런 경우에는 차라리 여러줄의 표현식과 조건문으로 표현하는것이 가독성면에서는 뛰어남을 보여줄 것이다.
구글의 파이썬 가이드에서 list comprehension
의 장점 및 단점을 더 확인해보자.
- List, Dict, and Set comprehensions as well as generator expressions provide a concise and efficient way to create container types and iterators without resorting to the use of traditional loops, map(), filter(), or lambda.
- Simple comprehensions can be clearer and simpler than other dict, list, or set creation techniques.
for loop
, map()
, filter()
, lamda
를 사용하지 않고도 container
및 iterators
를 생성하는 간결하고 효율적인 방법을 제공한다.Complicated comprehensions or generator expressions can be hard to read.
복잡한 comprehension 또는 generator 표현은 가독성이 떨어진다!
cities = ["Tokyo", "Shanghai", "Jakarta", "Seoul", "Guangzhou", "Beijing", "Karachi", "Shenzhen", "Delhi" ]
아직 list comprehension 작성이 손에 익숙치 않아 list comprehension이 아닌 일반 for loop를 사용해서 어떤식으로 동작하면 되는지 구현해보았다.
cities = ["Tokyo","Shanghai","Jakarta","Seoul","Guangzhou","Beijing","Karachi","Shenzhen","Delhi"]
lists = []
for element in cities:
temp_list = list(element)
if temp_list[0] != "S":
lists.append(element)
print(lists)
먼저 주어진 list인 cities를 for를 사용해 요소로 구분지었다.이 단계에서 print해보면 도시 이름 하나씩 구분되어 출력된다. 이 구분지은 요소를 또다시 list화 시켜서 출력을 확인하면 도시이름 스펠링이 하나씩 구분되어 temp_list
에 저장되어 있는것을 확인할 수 있다. 이제 대문자 "S"
만 없으면 되기 때문에 S
가 있는지 없는지 조건문을 사용해 비교하고 없으면 빈 리스트에 추가시켜주었다.
위의 로직을 그대로 list comprehension으로 구현해보자.
print([ element for element in cities if "S" not in element ])
[표현식 for 원소 in 반복 가능한 객체 if문]
위 형태에 따라서 작성해보았다.
1. [] 리스트를 만들고 안에 cities의 요소들을 뽑아 낼 반복문을 작성한다.
[ for element in cities ]
S
가 있는지 없는지 확인하기 위해 if ~ not in ~
를 사용했다.[ for element in cities if "S" not in element ]
element
를 표현해준다.[ element for element in cities if "S" not in element ]
population_of_city = [
('Tokyo', 36923000),
('Shanghai', 34000000),
('Jakarta', 30000000),
('Seoul', 25514000),
('Guangzhou', 25000000),
('Beijing', 24900000),
('Karachi', 24300000),
('Shenzhen', 23300000),
('Delhi', 21753486)
]
Comprehension 없이 풀어보면 다음과 같다.
print(dict(population_of_city))
이건 comprehension을 사용하지 않았음에도 상당히 간결한 코드로 작성이 가능하다.
Dict Comprehension은 다음과 같은 문법을 갖는다.
{Key:Value for 요소 in 입력sequence [if 조건식]}
for element in population_of_city:
print(element)
element[0]:element[1]
print({element[0]:element[1] for element in population_of_city})
결과는 동일하다.