# 예를 들어 소프트웨어 라디오를 사용해 신호를 내보낸다고 하자.
# 다음 코드는 주어진 간격과 진폭에 따른 사인파값을 생성한다.
import math
def wave(amplitude, steps):
step_size = 2 * math.pi / steps # 2라디안/단계 수
for step in range(steps):
radians = step * step_size
fraction = math.sin(radians)
output = amplitude * fraction
yield output
# wave 제너레이터를 이터레이션하면서 진폭이 고정된 파형 신호를 송신할 수 있다.
def transmit(output):
if output is None:
print(f'출력: None')
else:
print(f'출력: {output:>5.1f}')
def run(it):
for output in it:
transmit(output)
run(wave(3.0, 8))
출력: 0.0
출력: 2.1
출력: 3.0
출력: 2.1
출력: 0.0
출력: -2.1
출력: -3.0
출력: -2.1
def my_generator():
received = yield 1
print(f'받은 값 = {received}')
it = iter(my_generator())
output = next(it) # 첫 번째 제너레이터 출력을 얻는다
print(f'출력값 = {output}')
try:
next(it) # 종료될 때까지 제너레이터를 실행한다
except StopIteration:
pass
출력값 = 1
받은 값 = None
def my_generator():
received = yield 1
print(f'받은 값 = {received}')
it = iter(my_generator())
try:
print(next(it)) # 종료될 때까지 제너레이터를 실행한다
except StopIteration:
pass
try:
print(next(it)) # 첫 번째 제너레이터 출력을 얻는다
except StopIteration:
pass
1
받은 값 = None
#
it = iter(my_generator())
output = it.send(None) # 첫 번째 제너레이터 출력을 얻는다
print(f'출력값 = {output}')
try:
it.send('안녕!') # 값을 제너레이터에 넣는다
except StopIteration:
pass
try:
it.send(None)
except StopIteration:
print('stop')
출력값 = 1
받은 값 = 안녕!
stop
import math
def wave_modulating(steps):
step_size = 2 * math.pi / steps
amplitude = yield # 초기 진폭을 받는다
for step in range(steps):
radians = step * step_size
fraction = math.sin(radians)
output = amplitude * fraction
amplitude = yield output # 다음 진폭을 받는다
def run_modulating(it):
amplitudes = [
None, 7, 7, 7, 2, 2, 2, 2, 10, 10, 10, 10, 10]
for amplitude in amplitudes:
output = it.send(amplitude)
transmit(output)
run_modulating(wave_modulating(12))
출력: None
출력: 0.0
출력: 3.5
출력: 6.1
출력: 2.0
출력: 1.7
출력: 1.0
출력: 0.0
출력: -5.0
출력: -8.7
출력: -10.0
출력: -8.7
출력: -5.0
코드를 처음 봤을 때 이해하기 어려움,
대입문의 오른쪽에 yield 를 사용하는 것은 직관적이지 않다.
제너레이터 고급 기능을 잘 모를 경우 send와 yield 사이 연결을 알아보기 어렵다.
프로그램 요구 사항이 더 복잡해졌다고 가정하자.
단순 사인파를 반송파로 사용하는 대신, 여러 신호의 시퀀스로 이뤄진 복잡한 파형을 사용해야 한다.
이런 동작을 구현하는 한 가지 방법은 yield from식을 사용해 여러 제너레이터를 합성하는 것이다.
# 다음은 진폭이 고정된 더 단순한 경우에 yield from이 잘 작동하는 지 확인하기 위한 코드
def complex_wave():
yield from wave(7.0, 3)
yield from wave(2.0, 4)
yield from wave(10.0, 5)
def wave(amplitude, steps):
step_size = 2 * math.pi / steps # 2라디안/단계 수
for step in range(steps):
radians = step * step_size
fraction = math.sin(radians)
output = amplitude * fraction
yield output
def run(it):
for output in it:
transmit(output)
run(complex_wave())
출력: 0.0
출력: 6.1
출력: -6.1
출력: 0.0
출력: 2.0
출력: 0.0
출력: -2.0
출력: 0.0
출력: 9.5
출력: 5.9
출력: -5.9
출력: -9.5
def complex_wave_modulating():
yield from wave_modulating(3)
yield from wave_modulating(4)
yield from wave_modulating(5)
def wave_modulating(steps):
step_size = 2 * math.pi / steps
amplitude = yield # 초기 진폭을 받는다
for step in range(steps):
radians = step * step_size
fraction = math.sin(radians)
output = amplitude * fraction
amplitude = yield output
def run_modulating(it):
amplitudes = [
None, 7, 7, 7, 2, 2, 2, 2, 10, 10, 10, 10, 10]
for amplitude in amplitudes:
output = it.send(amplitude)
transmit(output)
run_modulating(complex_wave_modulating())
출력: None
출력: 0.0
출력: 6.1
출력: -6.1
출력: None
출력: 0.0
출력: 2.0
출력: 0.0
출력: -10.0
출력: None
출력: 0.0
출력: 9.5
출력: 5.9
여러 none값이 출력되었다.
yield from 식이 끝날 때마다 다음 yield from 식이 실행 된다.
각 내포된 제너레이터는 send 메서드 호출로부처 값을 받기 위해 아무런 값도 만들어내지 않는 단순한 yield식으로 시작한다.
이로 인해 부모 제너레이터가 자식 제너레이터를 옮겨갈 때마다 None이 출력된다.
yield from과 send를 따로 사용할 때는 제대로 작용하던 특성이 두 기능을 함께 사용할 때는 깨지기 때문이다.
run-modulation함수의 복잡도를 증가시켜서 이런 None 문제를 우회하는 방법이 있다.
하지만 이 문제를 해결하기 위해 그런 노력을 기울일 만한 가치는 없다.
send가 어떻게 작동하는지 배우는 것도 어려운데 yield from의 함정까지 이해해야 한다면 악화된다.
send를 사용하지말고 더 단순한 접근 방법을 택할 것을 권한다.
def wave_cascading(amplitude_it, steps):
step_size = 2 * math.pi / steps
for step in range(steps):
radians = step * step_size
fraction = math.sin(radians)
amplitude = next(amplitude_it) # 다음 입력 받기
output = amplitude * fraction
yield output
def complex_wave_cascading(amplitude_it):
yield from wave_cascading(amplitude_it, 3)
yield from wave_cascading(amplitude_it, 4)
yield from wave_cascading(amplitude_it, 5)
def run_cascading():
amplitudes = [7, 7, 7, 2, 2, 2, 2, 10, 10, 10, 10, 10]
it = complex_wave_cascading(iter(amplitudes))
for amplitude in amplitudes:
output = next(it)
transmit(output)
run_cascading()
출력: 0.0
출력: 6.1
출력: -6.1
출력: 0.0
출력: 2.0
출력: 0.0
출력: -2.0
출력: 0.0
출력: 9.5
출력: 5.9
출력: -5.9
출력: -9.5