Advanced Python - list comprehension [1/7]

Seob·2020년 7월 22일
0

TIL

목록 보기
17/36

List Comprehension? 🤷🏻‍♂️

리스트 컴프리헨션이란 새로운 리스트를 만들 때 사용할 수 있는 간단한 표현식으로 리스트와 마찬가지로 대괄호 [, ] 를 사용하여 작성한다.

만들고자 하는 원소를 표현하는 표현식으로 시작하여 for 루프가 뒤에 따라오는 형식을 가지고 조건문을 추가하여 조건문을 포함한 형식이 될 수도 있다.

[ 표현식 for 원소 in 반복 가능한 객체 ]
[ 표현식 for 원소 in 반복 가능한 객체 if문 ]

장점🥰

TIL - How to Python "pythonically" 에서도 예제를 다룬 적이 있었는데 이번에는 더 간단한 예제로 장점을 살펴보겠다.

1부터 10까지 정수를 가지는 리스트를 만들때 보통 이렇게 할 것이다.

lst = []
for i in range(1, 11):
    lst.append(i)
print(lst)
>>>
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

하지만 리스트 컴프리헨션으로 표현하면 다음과 같이 간결하게 작성할 수 있다.

lst = [i for i in range(1, 11)]
print(lst)
>>>
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

여기에 if 조건문을 넣어서 짝수만 리스트에 넣으려면 다음과 같이 작성할 수 있다.

lst = []
for i in range(1, 11):
    if i % 2 == 0:
        lst.append(i)
print(lst)
>>>
[2, 4, 6, 8, 10]
lst = [i for i in range(1, 11) if i % 2 == 0]
print(lst)
>>>
[2, 4, 6, 8, 10]

성능🤓

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 time =  0.061313478 milliseconds
list_comprehension time =  0.037402701999999996 milliseconds

위의 코드를 보면 for loop 은 0.061 밀리초, list comprehension은 0.037 밀리초로 절반가까이 빨라졌다.

하지만 리스트 컴프리핸션이 항상 좋은것 만은 아니다. 간단한 컴프리핸션은 더 간단하고 명확할 수 있지만 2중 for loop을 써야 하거나, 복잡한 조건이 들어가야할 경우에는 가독성을 위해서라도 리스트 컴프리핸션을 쓰지 않는게 더 좋을 수도 있다.

Okay to use 👌🏻

Yes:
  result = [mapping_expr for value in iterable if filter_expr]

  result = [{'key': value} for value in iterable
            if a_long_filter_expression(value)]

  result = [complicated_transform(x)
            for x in iterable if predicate(x)]

  descriptive_name = [
      transform({'key': key, 'value': value}, color='black')
      for key, value in generate_iterable(some_input)
      if complicated_condition_is_met(key, value)
  ]

  result = []
  for x in range(10):
      for y in range(5):
          if x * y > 10:
              result.append((x, y))

  return {x: complicated_transform(x)
          for x in long_generator_function(parameter)
          if x is not None}

  squares_generator = (x**2 for x in range(10))

  unique_names = {user.name for user in users if user is not None}

  eat(jelly_bean for jelly_bean in jelly_beans
      if jelly_bean.color == 'black')

Not okay to use 🤔

No:
  result = [complicated_transform(
                x, some_argument=x+1)
            for x in iterable if predicate(x)]

  result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

  return ((x, y, z)
          for x in range(5)
          for y in range(5)
          if x != y
          for z in range(5)
          if y != z)

cities = ['Tokyo', 'Shanghai', 'Jakarta', 'Seoul',
          'Guangzhou', 'Beijing', 'Karachi', 'Shenzhen', 'Delhi']
without_s = [i for i in cities if i[0:1] == 'S']
print(without_s)

population_of_city = [('Tokyo', 36923000), ('Shanghai', 34000000), ('Jakarta', 30000000), ('Seoul', 25514000), (
    'Guangzhou', 25000000), ('Beijing', 24900000), ('Karachi', 24300000), ('Shenzhen', 23300000), ('Delhi', 21753486)]

d = {k: v for k, v in population_of_city}
print(d)

>>>
['Shanghai', 'Seoul', 'Shenzhen']
{'Tokyo': 36923000, 'Shanghai': 34000000, 'Jakarta': 30000000, 'Seoul': 25514000, 'Guangzhou': 25000000, 'Beijing': 24900000, 'Karachi': 24300000, 'Shenzhen': 23300000, 'Delhi': 21753486}

위의 코드는 리스트 컴프리헨션을 사용하여 도시 이름이 S 로 시작하는 리스트를 만들었고, 튜플로 주어진 도시 이름과 인구수를 딕셔너리 컴프리헨션을 사용한 함수를 작성한 결과이다.

profile
Hello, world!

0개의 댓글