이터레이터의 실제 사용 사례
이제 이터레이터를 만들고 사용하는 방법을 이해했으므로, 이터레이터가 코드를 개선할 수 있는 몇 가지 실용적인 실제 사용 사례를 살펴보겠습니다.
제너레이터를 사용한 지연 평가
제너레이터는 yield 문을 사용하는 함수로 생성된 특수한 유형의 이터레이터입니다. 이를 통해 값을 즉시 생성할 수 있으며, 이는 전체 목록을 만드는 것보다 메모리 효율적일 수 있습니다.
generator_example.py라는 파일을 생성합니다.
def squared_numbers(n):
"""Generate squares of numbers from 1 to n."""
for i in range(1, n + 1):
yield i * i
## Create a generator for squares of numbers 1 to 10
squares = squared_numbers(10)
## squares is a generator object (a type of iterator)
print(f"Type of squares: {type(squares)}")
## Use next() to get values from the generator
print("\nGetting values with next():")
print(next(squares)) ## 1
print(next(squares)) ## 4
print(next(squares)) ## 9
## Use a for loop to get the remaining values
print("\nGetting remaining values with a for loop:")
for square in squares:
print(square)
## The generator is now exhausted, so this won't print anything
print("\nTrying to get more values (generator is exhausted):")
for square in squares:
print(square)
## Create a new generator and convert all values to a list at once
all_squares = list(squared_numbers(10))
print(f"\nAll squares as a list: {all_squares}")
코드를 실행합니다.
python3 ~/project/generator_example.py
다음과 같은 결과를 볼 수 있습니다.
Type of squares: <class 'generator'>
Getting values with next():
1
4
9
Getting remaining values with a for loop:
16
25
36
49
64
81
100
Trying to get more values (generator is exhausted):
All squares as a list: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
제너레이터는 간단한 경우에 이터레이터를 만드는 더 간결한 방법입니다. 제너레이터는 자동으로 이터레이터 프로토콜을 구현합니다.
대용량 데이터 세트 처리
이터레이터는 한 번에 하나의 요소로 작업할 수 있으므로 대용량 데이터 세트를 처리하는 데 적합합니다. 온도에 대한 대용량 데이터 세트를 시뮬레이션하는 예제를 만들어 보겠습니다.
data_processing.py라는 파일을 생성합니다.
import random
import time
def temperature_data_generator(days, start_temp=15.0, max_variation=5.0):
"""Generate simulated hourly temperature data for a number of days."""
hours_per_day = 24
total_hours = days * hours_per_day
current_temp = start_temp
for hour in range(total_hours):
## Simulate temperature variations
day_progress = (hour % hours_per_day) / hours_per_day ## 0.0 to 1.0 through the day
## Temperature is generally cooler at night, warmer during day
time_factor = -max_variation/2 * (
-2 * day_progress + 1 if day_progress < 0.5
else 2 * day_progress - 1
)
## Add some randomness
random_factor = random.uniform(-1.0, 1.0)
current_temp += time_factor + random_factor
current_temp = max(0, min(40, current_temp)) ## Keep between 0-40°C
yield (hour // hours_per_day, hour % hours_per_day, round(current_temp, 1))
def process_temperature_data():
"""Process a large set of temperature data using an iterator."""
print("Processing hourly temperature data for 30 days...")
print("-" * 50)
## Create our data generator
data_iterator = temperature_data_generator(days=30)
## Track some statistics
total_readings = 0
temp_sum = 0
min_temp = float('inf')
max_temp = float('-inf')
## Process the data one reading at a time
start_time = time.time()
for day, hour, temp in data_iterator:
## Update statistics
total_readings += 1
temp_sum += temp
min_temp = min(min_temp, temp)
max_temp = max(max_temp, temp)
## Just for demonstration, print a reading every 24 hours
if hour == 12: ## Noon each day
print(f"Day {day+1}, 12:00 PM: {temp}°C")
processing_time = time.time() - start_time
## Calculate final statistics
avg_temp = temp_sum / total_readings if total_readings > 0 else 0
print("-" * 50)
print(f"Processed {total_readings} temperature readings in {processing_time:.3f} seconds")
print(f"Average temperature: {avg_temp:.1f}°C")
print(f"Temperature range: {min_temp:.1f}°C to {max_temp:.1f}°C")
## Run the temperature data processing
process_temperature_data()
코드를 실행합니다.
python3 ~/project/data_processing.py
다음과 유사한 출력을 볼 수 있습니다 (정확한 온도는 무작위성으로 인해 달라집니다).
Processing hourly temperature data for 30 days...
--------------------------------------------------
Day 1, 12:00 PM: 17.5°C
Day 2, 12:00 PM: 18.1°C
Day 3, 12:00 PM: 17.3°C
...
Day 30, 12:00 PM: 19.7°C
--------------------------------------------------
Processed 720 temperature readings in 0.012 seconds
Average temperature: 18.2°C
Temperature range: 12.3°C to 24.7°C
이 예제에서는 이터레이터를 사용하여 720 개의 온도 판독값 (24 시간 × 30 일) 의 시뮬레이션된 데이터 세트를 한 번에 메모리에 모든 데이터를 저장하지 않고 처리하고 있습니다. 이터레이터는 각 판독값을 필요에 따라 생성하여 코드를 더 메모리 효율적으로 만듭니다.
이터레이터를 사용한 데이터 파이프라인 구축
이터레이터를 함께 연결하여 데이터 처리 파이프라인을 만들 수 있습니다. 다음 파이프라인을 구축해 보겠습니다.
- 숫자를 생성합니다.
- 홀수를 필터링합니다.
- 나머지 짝수를 제곱합니다.
- 출력을 특정 결과 수로 제한합니다.
data_pipeline.py라는 파일을 생성합니다.
def generate_numbers(start, end):
"""Generate numbers in the given range."""
print(f"Starting generator from {start} to {end}")
for i in range(start, end + 1):
print(f"Generating: {i}")
yield i
def filter_even(numbers):
"""Filter for even numbers only."""
for num in numbers:
if num % 2 == 0:
print(f"Filtering: {num} is even")
yield num
else:
print(f"Filtering: {num} is odd (skipped)")
def square_numbers(numbers):
"""Square each number."""
for num in numbers:
squared = num ** 2
print(f"Squaring: {num} → {squared}")
yield squared
def limit_results(iterable, max_results):
"""Limit the number of results."""
count = 0
for item in iterable:
if count < max_results:
print(f"Limiting: keeping item #{count+1}")
yield item
count += 1
else:
print(f"Limiting: reached maximum of {max_results} items")
break
## Create our data pipeline
print("Creating data pipeline...\n")
pipeline = (
limit_results(
square_numbers(
filter_even(
generate_numbers(1, 10)
)
),
3 ## Limit to 3 results
)
)
## Execute the pipeline by iterating through it
print("\nExecuting pipeline and collecting results:")
print("-" * 50)
results = list(pipeline)
print("-" * 50)
print(f"\nFinal results: {results}")
코드를 실행합니다.
python3 ~/project/data_pipeline.py
다음과 같은 결과를 볼 수 있습니다.
Creating data pipeline...
Executing pipeline and collecting results:
--------------------------------------------------
Starting generator from 1 to 10
Generating: 1
Filtering: 1 is odd (skipped)
Generating: 2
Filtering: 2 is even
Squaring: 2 → 4
Limiting: keeping item #1
Generating: 3
Filtering: 3 is odd (skipped)
Generating: 4
Filtering: 4 is even
Squaring: 4 → 16
Limiting: keeping item #2
Generating: 5
Filtering: 5 is odd (skipped)
Generating: 6
Filtering: 6 is even
Squaring: 6 → 36
Limiting: keeping item #3
Generating: 7
Filtering: 7 is odd (skipped)
Generating: 8
Filtering: 8 is even
Squaring: 8 → 64
Limiting: reached maximum of 3 items
--------------------------------------------------
Final results: [4, 16, 36]
이 파이프라인 예제는 이터레이터를 함께 연결하여 데이터 처리 워크플로를 형성하는 방법을 보여줍니다. 파이프라인의 각 단계는 한 번에 하나의 항목을 처리하여 다음 단계로 전달합니다. 파이프라인은 실제로 결과를 사용할 때까지 (이 경우 목록으로 변환하여) 데이터를 처리하지 않습니다.
주요 장점은 파이프라인 단계 사이에 중간 목록이 생성되지 않아 대용량 데이터 세트에서도 이 접근 방식이 메모리 효율적이라는 것입니다.