KR_Generator - somaz94/python-study GitHub Wiki
์ ๋๋ ์ดํฐ๋ ์ดํฐ๋ ์ดํฐ๋ฅผ ์์ฑํ๋ ํจ์์ด๋ค. yield ๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ๋์ฉ ๋ฐํํ๋ค.
# ๊ธฐ๋ณธ ์ ๋๋ ์ดํฐ ํจ์
def number_generator():
yield 1
yield 2
yield 3
# ์ฌ์ฉ
gen = number_generator()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# print(next(gen)) # StopIteration ์์ธ ๋ฐ์
# for ๋ฃจํ๋ก ์ฌ์ฉ
for num in number_generator():
print(num) # 1, 2, 3 ์์๋๋ก ์ถ๋ ฅ
# ์ผ๋ฐ ํจ์์ ๋น๊ต
def get_numbers_list():
return [1, 2, 3] # ๋ชจ๋ ๊ฐ์ ํ๊บผ๋ฒ์ ๋ฉ๋ชจ๋ฆฌ์ ์์ฑ
def get_numbers_generator():
yield 1
yield 2
yield 3 # ๊ฐ์ ํ์ํ ๋ ํ๋์ฉ ์์ฑ
โ
ํน์ง:
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์
- ์ง์ฐ ํ๊ฐ (๊ฐ์ด ํ์ํ ๋๋ง ๊ณ์ฐ)
- ์ดํฐ๋ ์ดํฐ ์์ฑ
- ํ ๋ฒ๋ง ์ํ ๊ฐ๋ฅ
- ํจ์์ ์ํ ๋ณด์กด
yield๋ ํจ์์ ์คํ์ ์ผ์ ์ค๋จํ๊ณ ๊ฐ์ ๋ฐํํ๋ฉฐ, ๋ค์ ํธ์ถ ์ ์ค๋จ๋ ์ง์ ๋ถํฐ ์คํ์ ์ฌ๊ฐํ๋ค.
def countdown(n):
print("์นด์ดํธ๋ค์ด ์์!")
while n > 0:
print(f"{n} ๋ฐํ ์ค๋น ์ค...")
yield n
print(f"{n} ๋ฐํ ์๋ฃ, ๊ณ์ ์คํ")
n -= 1
print("์นด์ดํธ๋ค์ด ์ข
๋ฃ!")
# ์ฌ์ฉ
counter = countdown(3)
print(next(counter)) # ์นด์ดํธ๋ค์ด ์์! / 3 ๋ฐํ ์ค๋น ์ค... / 3
print(next(counter)) # 3 ๋ฐํ ์๋ฃ, ๊ณ์ ์คํ / 2 ๋ฐํ ์ค๋น ์ค... / 2
print(next(counter)) # 2 ๋ฐํ ์๋ฃ, ๊ณ์ ์คํ / 1 ๋ฐํ ์ค๋น ์ค... / 1
# next(counter) # 1 ๋ฐํ ์๋ฃ, ๊ณ์ ์คํ / ์นด์ดํธ๋ค์ด ์ข
๋ฃ! / StopIteration
# ํผ๋ณด๋์น ์์ด ์์ฑ
def fibonacci(limit):
a, b = 0, 1
count = 0
while count < limit:
yield a
a, b = b, a + b
count += 1
for fib in fibonacci(10):
print(fib, end=' ') # 0 1 1 2 3 5 8 13 21 34
โ
ํน์ง:
- ์ํ ์ ์ง (ํจ์์ ๋ก์ปฌ ๋ณ์๊ฐ ๋ณด์กด๋จ)
- ์คํ ์ค๋จ ๋ฐ ์ฌ๊ฐ
- ๊ฐ ๋ฐํ
- ์ปจํ ์คํธ ๋ณด์กด
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ์ํ์ค ์์ฑ
๋ฆฌ์คํธ ์ปดํ๋ฆฌํจ์
๊ณผ ์ ์ฌํ์ง๋ง ์๊ดํธ ()๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ์ ๋๋ ์ดํฐ๋ฅผ ์์ฑํ๋ค.
# ์ ๋๋ ์ดํฐ ํํ์
squares = (x**2 for x in range(10))
print(next(squares)) # 0
print(next(squares)) # 1
# ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๋น๊ต
import sys
list_comp = [x**2 for x in range(1000000)] # ๋ฉ๋ชจ๋ฆฌ ๋ง์ด ์ฌ์ฉ
gen_exp = (x**2 for x in range(1000000)) # ๋ฉ๋ชจ๋ฆฌ ์ ๊ฒ ์ฌ์ฉ
print(f"๋ฆฌ์คํธ ํฌ๊ธฐ: {sys.getsizeof(list_comp)} ๋ฐ์ดํธ")
print(f"์ ๋๋ ์ดํฐ ํฌ๊ธฐ: {sys.getsizeof(gen_exp)} ๋ฐ์ดํธ")
# ํํฐ๋ง๊ณผ ํจ๊ป ์ฌ์ฉ
even_squares = (x**2 for x in range(10) if x % 2 == 0)
print(list(even_squares)) # [0, 4, 16, 36, 64]
# ์ค์ฒฉ ์ ๋๋ ์ดํฐ ํํ์
matrix = ((i*j for j in range(3)) for i in range(3))
for row in matrix:
print(list(row)) # [0, 0, 0], [0, 1, 2], [0, 2, 4]
โ
ํน์ง:
- ๊ฐ๋จํ ๋ฌธ๋ฒ
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ
- ์ง์ฐ ๊ณ์ฐ
- ํํฐ๋ง ์ง์
- ์ค์ฒฉ ๊ฐ๋ฅ
- ์ผํ์ฑ ์ดํฐ๋ ์ด์
์ ๋๋ ์ดํฐ๋ next() ์ธ์๋ ๋ค์ํ ๋ฉ์๋๋ฅผ ํตํด ์๋ฐฉํฅ ํต์ ๊ณผ ์ ์ด๊ฐ ๊ฐ๋ฅํ๋ค.
def counter():
i = 0
while True:
val = (yield i) # yield ํํ์
if val is not None:
i = val
else:
i += 1
c = counter()
print(next(c)) # 0 (์ฒซ ๋ฒ์งธ yield๊น์ง ์คํ)
print(c.send(10)) # 10 (๊ฐ์ ๋ณด๋ด๊ณ ๋ค์ yield๊น์ง ์คํ)
print(next(c)) # 11
print(next(c)) # 12
# throw() ๋ฉ์๋๋ก ์์ธ ์ ๋ฌ
def exception_handler():
try:
while True:
try:
x = yield
except ValueError:
print("ValueError ์ฒ๋ฆฌ๋จ")
else:
print(f"๊ฐ ๋ฐ์: {x}")
finally:
print("์ ๋๋ ์ดํฐ ์ข
๋ฃ")
g = exception_handler()
next(g) # ์ฒซ ๋ฒ์งธ yield๊น์ง ์งํ
g.send(1) # "๊ฐ ๋ฐ์: 1"
g.throw(ValueError) # "ValueError ์ฒ๋ฆฌ๋จ"
g.close() # "์ ๋๋ ์ดํฐ ์ข
๋ฃ"
# ์ฝ๋ฃจํด์ผ๋ก ์ฌ์ฉ
def grep(pattern):
print(f"ํจํด '{pattern}' ๊ฒ์ ์ค...")
while True:
line = (yield)
if pattern in line:
print(line)
search = grep("python")
next(search) # ์ฒซ ๋ฒ์งธ yield๊น์ง ์คํ
search.send("hello world") # ์๋ฌด๊ฒ๋ ์ถ๋ ฅ ์ ํจ
search.send("python is awesome") # "python is awesome" ์ถ๋ ฅ
search.close() # ์ ๋๋ ์ดํฐ ์ข
๋ฃ
โ
ํน์ง:
- ์๋ฐฉํฅ ํต์ (send)
- ์ํ ๋ณ๊ฒฝ
- ์์ธ ์ฃผ์ (throw)
- ์ข ๋ฃ ์ฒ๋ฆฌ (close)
- ์ฝ๋ฃจํด ๊ตฌํ
- ๋ณต์กํ ์ ์ด ํ๋ฆ ์ฒ๋ฆฌ
์ฌ๋ฌ ์ ๋๋ ์ดํฐ๋ฅผ ์ฐ๊ฒฐํ์ฌ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ ์ ์๋ค.
def numbers():
for i in range(1, 4):
yield i
def squares(nums):
for n in nums:
yield n**2
def add_one(nums):
for n in nums:
yield n + 1
# ์ฒด์ด๋
chain = add_one(squares(numbers()))
print(list(chain)) # [2, 5, 10]
# yield from์ ์ฌ์ฉํ ์ฒด์ด๋
def numbers_gen():
yield from range(1, 4)
def squares_gen(nums):
for n in nums:
yield n**2
# ์ ๋๋ ์ดํฐ๋ก ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
def process_file(filename):
with open(filename, 'r') as f:
yield from f # ํ์ผ์ ๊ฐ ๋ผ์ธ์ ์์ฑ
def grep_filter(lines, pattern):
for line in lines:
if pattern in line:
yield line
def replace_text(lines, old, new):
for line in lines:
yield line.replace(old, new)
# ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ ์์
# pipeline = replace_text(grep_filter(process_file('log.txt'), 'ERROR'), 'ERROR', 'CRITICAL')
โ
ํน์ง:
- ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ
- ๋ชจ๋ํ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- yield from ํ์ฉ
- ์ฝ๋ ์ฌ์ฌ์ฉ
- ๋จ์ผ ์ฑ ์ ์์น ์ ์ฉ
- ๋ณต์กํ ๋ฐ์ดํฐ ๋ณํ ๋จ์ํ
์ ๋๋ ์ดํฐ๋ ๋ฌดํ ์ํ์ค ์์ฑ์ด๋ ๊ณ ๊ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ์ ์๋ค.
# ๋ฌดํ ์ํ์ค ์์ฑ
def infinite_counter(start=0):
while True:
yield start
start += 1
# ์ฌ๋ผ์ด์ฑ์ ์ํ itertools ์ฌ์ฉ
import itertools
counter = infinite_counter()
first_10 = list(itertools.islice(counter, 10))
print(first_10) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# ์ฌ๋ฌ ์ํ์ค ๋ณํฉ
def merge_sequences(*sequences):
"""์ฌ๋ฌ ์ํ์ค๋ฅผ ๋ฒ๊ฐ์๊ฐ๋ฉฐ ๋ณํฉ"""
iterators = [iter(seq) for seq in sequences]
active = len(iterators)
while active:
active = 0
for it in iterators:
try:
yield next(it)
active += 1
except StopIteration:
pass
# ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์ฒญํน
def chunk_data(iterable, size):
"""์ดํฐ๋ฌ๋ธ์ ์ง์ ๋ ํฌ๊ธฐ์ ์ฒญํฌ๋ก ๋ถํ """
iterator = iter(iterable)
while True:
chunk = list(itertools.islice(iterator, size))
if not chunk:
break
yield chunk
# ๋ฐฑํธ๋ํน ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ
def permutations(items):
"""์ฌ๊ท์ ์ ๋๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ ์์ด ์์ฑ"""
if len(items) <= 1:
yield items
else:
for i in range(len(items)):
for perm in permutations(items[:i] + items[i+1:]):
yield [items[i]] + perm
for p in permutations([1, 2, 3]):
print(p) # [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
โ
ํน์ง:
- ๋ฌดํ ์ํ์ค ์์ฑ
- ์ง์ฐ ํ๊ฐ ํ์ฉ
- itertools์ ํจ๊ป ์ฌ์ฉ
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์๊ณ ๋ฆฌ์ฆ
- ๋ณต์กํ ์ํ์ค ์ฒ๋ฆฌ
- ์ฌ๊ท์ ์ ๋๋ ์ดํฐ
์ ๋๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ๊ณผ ์ค์ ์์ฉ ์ฌ๋ก๋ฅผ ์์๋ณธ๋ค.
import time
import sys
# ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ธก์ ์์
def memory_usage_comparison():
# ํฐ ๋ฆฌ์คํธ vs ์ ๋๋ ์ดํฐ
start = time.time()
big_list = [i for i in range(10000000)]
list_memory = sys.getsizeof(big_list)
list_time = time.time() - start
start = time.time()
big_gen = (i for i in range(10000000))
gen_memory = sys.getsizeof(big_gen)
gen_time = time.time() - start
print(f"๋ฆฌ์คํธ ๋ฉ๋ชจ๋ฆฌ: {list_memory:,} ๋ฐ์ดํธ, ์์ฑ ์๊ฐ: {list_time:.4f}์ด")
print(f"์ ๋๋ ์ดํฐ ๋ฉ๋ชจ๋ฆฌ: {gen_memory:,} ๋ฐ์ดํธ, ์์ฑ ์๊ฐ: {gen_time:.4f}์ด")
print(f"๋ฉ๋ชจ๋ฆฌ ์ ์ฝ: {list_memory/gen_memory:.0f}๋ฐฐ")
# ๋์ฉ๋ ํ์ผ ์ฒ๋ฆฌ ์ต์ ํ
def process_large_file(filename, process_line):
"""๋์ฉ๋ ํ์ผ์ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌ"""
with open(filename, 'r') as file:
for line in file: # ํ์ผ ์ดํฐ๋ ์ดํฐ ํ์ฉ
yield process_line(line.strip())
# ์ง์ฐ ๊ณ์ฐ์ผ๋ก ์ฑ๋ฅ ํฅ์
def lazy_evaluation_example(n):
"""ํ์ํ ๊ฒฝ์ฐ์๋ง ๊ณ์ฐ ์ํ"""
print("์ ๋๋ ์ดํฐ ์์ฑ ์์")
def expensive_calculation(x):
print(f"{x}์ ๋ํ ๋น์ฉ์ด ๋ง์ด ๋๋ ๊ณ์ฐ ์ํ ์ค...")
time.sleep(0.1) # ๋น์ฉ์ด ๋ง์ด ๋๋ ์์
์๋ฎฌ๋ ์ด์
return x**2
# ๋ชจ๋ ๊ณ์ฐ์ ์ฆ์ ์ํํ์ง ์์
for i in range(n):
yield expensive_calculation(i)
# ์ฌ์ฉ ์:
# for result in lazy_evaluation_example(100):
# if result > 50: # ์กฐ๊ฑด์ ๋ง๋ ์ฒซ ๋ฒ์งธ ๊ฒฐ๊ณผ๋ง ํ์
# print(f"๊ฒฐ๊ณผ ์ฐพ์: {result}")
# break
โ
ํน์ง:
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ต์ ํ
- ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- ์ง์ฐ ๊ณ์ฐ์ผ๋ก ๋ถํ์ํ ์ฐ์ฐ ๋ฐฉ์ง
- ํ์ํ ๋งํผ๋ง ๊ณ์ฐ (์ค๊ฐ์ ์ค๋จ ๊ฐ๋ฅ)
- IO ๋ฐ์ด๋ ์์ ์ต์ ํ
- ์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
โ
๋ชจ๋ฒ ์ฌ๋ก:
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ์ด ํ์ํ ๋ ์ฌ์ฉ
- ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ํฉ
- ๋ฌดํ ์ํ์ค ์์ฑ ๊ฐ๋ฅ
- ํ ๋ฒ๋ง ์ํ ๊ฐ๋ฅํจ์ ์ฃผ์
- ์ ๋๋ ์ดํฐ ์ฒด์ด๋ ํ์ฉ
- ์ํ ๊ด๋ฆฌ ์ฃผ์
- ์์ธ ์ฒ๋ฆฌ ๊ตฌํ
- ํฐ ํ์ผ์ด๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ํ์ฉ
- yield from์ผ๋ก ์ ๋๋ ์ดํฐ ์์
- ์์ฐจ์ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ์ ์ ํฉ
- itertools ๋ชจ๋๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ
- ํ์ํ ๋๋ง ๊ณ์ฐํ๋ ์ง์ฐ ํ๊ฐ ํ์ฉ
- ๋ชจ๋ ํญ๋ชฉ์ ์ฌ๋ฌ ๋ฒ ์ ๊ทผํด์ผ ํ๋ค๋ฉด ๋ฆฌ์คํธ๋ก ๋ณํ ๊ณ ๋ ค
- ๋๋ฒ๊น ์ด ์ด๋ ค์ธ ์ ์์ผ๋ฏ๋ก ๋จ๊ณ๋ณ ํ ์คํธ ์ํ
- ๋ณต์กํ ์ฝ๋ฃจํด๋ณด๋ค๋ ๊ฐ๋จํ ์ ๋๋ ์ดํฐ๋ถํฐ ์์