Python 리스트 컴프리헨션과 메모리 절약: 더 빠르고 효율적인 코드 작성법

Python의 리스트 컴프리헨션(list comprehension)은 짧고 간결하게 리스트를 생성할 수 있는 문법입니다. 반복문과 조건문을 결합해 하나의 줄로 리스트를 생성하면서, 메모리를 절약할 수 있는 방법도 제공합니다. 이번 글에서는 리스트 컴프리헨션의 기본 개념과, 메모리 사용을 최소화하면서 효율적으로 코드를 작성할 수 있는 활용법을 설명합니다.


1. 리스트 컴프리헨션이란?

리스트 컴프리헨션은 하나의 표현식으로 리스트를 생성할 수 있는 Python의 특별한 문법입니다. 일반적인 for 반복문으로 리스트를 작성하는 방법보다 간결하고 읽기 쉽습니다.

기본 구조

리스트 컴프리헨션의 기본 구조는 다음과 같습니다:

[표현식 for 요소 in 반복 가능한 객체 if 조건]

위 구조에서, if 조건옵션으로 사용할 수 있는 필터입니다. 이 조건에 맞는 요소만 리스트에 포함됩니다.


2. 기본 예제: 리스트 컴프리헨션을 활용한 간결한 리스트 생성

다음은 for 반복문을 사용한 코드와 동일한 작업을 리스트 컴프리헨션으로 간단하게 작성한 예제입니다.

# 기존 방식
numbers = []
for i in range(10):
    if i % 2 == 0:
        numbers.append(i)

print(numbers)  # [0, 2, 4, 6, 8]

# 리스트 컴프리헨션 사용
numbers = [i for i in range(10) if i % 2 == 0]
print(numbers)  # [0, 2, 4, 6, 8]

결과

[0, 2, 4, 6, 8]

설명

  • 기존 방식에서는 for 반복문과 if 조건을 사용해 짝수를 골라내 리스트에 추가해야 했습니다.
  • 리스트 컴프리헨션을 사용하면 하나의 줄로 같은 결과를 얻을 수 있습니다. 간결하고, 읽기 쉬운 코드가 됩니다.

3. 메모리 절약하기: 제너레이터 표현식 사용

리스트 컴프리헨션은 메모리를 많이 사용하는 큰 리스트를 만들 때 부담이 될 수 있습니다. 이때는 제너레이터 표현식(generator expression)을 사용하여 메모리를 절약할 수 있습니다. 제너레이터는 모든 값을 한꺼번에 생성하지 않고 필요할 때마다 값을 생성하여 메모리 사용을 최소화합니다.

# 리스트 컴프리헨션 - 메모리 많이 사용
squares_list = [i * i for i in range(1000000)]

# 제너레이터 표현식 - 메모리 절약
squares_gen = (i * i for i in range(1000000))

print(sum(squares_list))  # 리스트 전체를 메모리에 올리므로 메모리 많이 사용
print(sum(squares_gen))   # 필요할 때마다 값을 생성하여 메모리 절약

설명

  • [i * i for i in range(1000000)]는 리스트 컴프리헨션으로 모든 제곱 값을 메모리에 저장합니다.
  • (i * i for i in range(1000000))는 제너레이터 표현식으로 값을 필요할 때마다 생성하므로 메모리 사용을 줄일 수 있습니다.
  • 큰 데이터나 무한 시퀀스를 처리할 때 제너레이터 표현식을 사용하면 메모리 부담 없이 작업을 수행할 수 있습니다.

4. 조건부 리스트 컴프리헨션으로 필터링 작업 단순화하기

리스트 컴프리헨션의 if 조건을 활용하면 필터링 작업을 간단하게 수행할 수 있습니다. 조건에 맞는 요소만 포함하도록 리스트를 생성해보겠습니다.

# 기존 방식
filtered_numbers = []
for i in range(20):
    if i % 3 == 0:
        filtered_numbers.append(i)

print(filtered_numbers)  # [0, 3, 6, 9, 12, 15, 18]

# 리스트 컴프리헨션 사용
filtered_numbers = [i for i in range(20) if i % 3 == 0]
print(filtered_numbers)  # [0, 3, 6, 9, 12, 15, 18]

결과

[0, 3, 6, 9, 12, 15, 18]

설명

  • if 조건을 사용하면 조건에 맞는 요소만 리스트에 추가할 수 있습니다.
  • 필터링 작업이 간단해지고, 코드를 읽는 사람도 조건이 무엇인지 쉽게 이해할 수 있어 가독성이 높아집니다.

5. 리스트 컴프리헨션으로 중첩 반복문 처리하기

중첩 반복문이 필요할 때도 리스트 컴프리헨션을 사용하면 코드를 훨씬 짧고 간결하게 만들 수 있습니다.

# 기존 방식
pairs = []
for i in range(3):
    for j in range(3):
        pairs.append((i, j))

print(pairs)  # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

# 리스트 컴프리헨션 사용
pairs = [(i, j) for i in range(3) for j in range(3)]
print(pairs)  # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

결과

[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

설명

  • 리스트 컴프리헨션을 사용하면 중첩 반복문을 간결하게 표현할 수 있습니다.
  • (i, j) for i in range(3) for j in range(3)ij의 모든 조합을 리스트로 만듭니다. 코드가 짧아지고, 반복문이 한 줄로 정리되어 가독성이 높아집니다.

6. 조건문을 이용해 값 변환과 필터링을 동시에 수행하기

리스트 컴프리헨션은 조건에 따라 값을 변환하면서 리스트를 만들 수 있어, 코드가 간단해지고 실행 속도가 빨라집니다.

# 짝수는 그대로, 홀수는 제곱하여 리스트에 추가
numbers = [i if i % 2 == 0 else i * i for i in range(10)]
print(numbers)  # [0, 1, 2, 9, 4, 25, 6, 49, 8, 81]

결과

[0, 1, 2, 9, 4, 25, 6, 49, 8, 81]

설명

  • i if i % 2 == 0 else i * i는 짝수는 그대로 추가하고, 홀수는 제곱하여 리스트에 추가합니다.
  • 리스트 컴프리헨션을 사용하면 조건에 맞는 값을 쉽게 변환할 수 있어 필터링과 값 변환 작업을 동시에 수행할 수 있습니다.

7. 다중 조건을 사용해 복잡한 필터링 수행하기

리스트 컴프리헨션에서 if 조건을 여러 개 사용할 수 있어 다중 조건 필터링을 간단히 처리할 수 있습니다.

# 3의 배수이면서 짝수인 수만 리스트에 포함
numbers = [i for i in range(30) if i % 3 == 0 if i % 2 == 0]
print(numbers)  # [0, 6, 12, 18, 24]

결과

[0, 6, 12, 18, 24]

설명

  • if i % 3 == 0 if i % 2 == 03의 배수이면서 짝수인 조건을 만족하는 값을 필터링합니다.
  • 다중 조건을 사용할 수 있어, 복잡한 조건이 필요한 필터링 작업도 한 줄로 간단하게 작성할 수 있습니다.

요약: 리스트 컴프리헨션과 메모리 절약

Python의 리스트 컴프리헨션은 간결하게 리스트를 생성하면서도 복잡한 조건을 적용하거나 필터링 작업을 수행할 수 있어 코드 가독성이 높아집니다. 또한, 메모리를 효율적으로 사용하는 제너레이터 표현식을 통해 대용량 데이터를 다룰 때도 부담을 줄일 수 있습니다.

리스트 컴프리헨션의 장점은 다음과 같습니다:

  1. 간결한 코드 작성: 반복문과 조건문을 하나의 표현식으로 작성하여 코드가 짧아지고 가독성이 높아집니다.
  2. 메모리 절약: 제너레이터 표현식을 사용하여 큰 데이터를 메모리에 부담 없이 다룰 수 있습니다.
  3. 필터링과 변환의 동시 수행: 조건문을 통해 데이터를 필터링하거나 변환하는 작업을 한 줄로 작성할 수 있습니다.

리스트 컴프리헨션과 제너레이터 표현식을 활용해 더 효율적이고 빠른 Python 코드를 작성해보세요!

+ Recent posts