5.1 Python 언어의 핵심

실습 · 연습문제 2개

지연 계산하는 batch generator lazy-batches

샘플이 하나씩 나오는 iterable(파일의 줄, 센서 스트림, 다른 generator)을 받아 크기 batch_size의 리스트로 묶어 내보내는 generator 함수 batched(samples, batch_size)를 완성한다.

list(batched(range(7), 3))
# [[0, 1, 2], [3, 4, 5], [6]]

규칙은 다음과 같다.

  • 마지막 batch는 batch_size보다 작을 수 있다. 빈 batch는 내보내지 않는다.
  • batch_size가 1보다 작으면 ValueError를 낸다. 이 검사는 첫 batch를 요청하기 전, 함수를 호출하는 순간 이루어져야 한다.
  • 입력을 한꺼번에 읽지 않는다. 끝이 없는 스트림(itertools.count())에서도 앞의 몇 batch를 꺼낼 수 있어야 하고, batch 하나를 꺼낼 때 입력에서 정확히 그 batch에 필요한 만큼만 읽어야 한다.
  • 입력은 리스트가 아닐 수 있다. 인덱싱(samples[i])이나 len(samples)를 쓰지 않는다.

힌트: iter()로 iterator를 만든 뒤 itertools.islice로 필요한 만큼만 꺼낼 수 있다. generator 함수 본문은 첫 next() 호출 때 실행되기 시작한다는 점이 인자 검사 규칙과 어떻게 얽히는지 생각한다.

원본을 건드리지 않는 설정 병합 merge-config

실험 설정은 흔히 중첩 dict로 둔다. 기본 설정 base에 실험별 변경 사항 overrides를 덮어써 새 설정을 만드는 함수 merge_config(base, overrides)를 완성한다.

base = {"model": {"width": 64, "depth": 2}, "tags": ["baseline"]}
overrides = {"model": {"depth": 4}, "seed": 1}
merge_config(base, overrides)
# {"model": {"width": 64, "depth": 4}, "tags": ["baseline"], "seed": 1}

규칙은 다음과 같다.

  • 같은 키의 값이 둘 다 dict이면 재귀적으로 병합한다.
  • 그 밖의 경우(값이 dict가 아니거나 한쪽만 dict)에는 overrides의 값이 이긴다.
  • base와 overrides는 어떤 깊이에서도 바뀌면 안 된다.
  • 반환한 설정은 입력과 객체를 공유하지 않아야 한다. 반환값의 리스트에 원소를 추가해도 base의 리스트가 바뀌면 안 된다.

테스트는 결과 값뿐 아니라, 병합 뒤 입력이 그대로인지와 결과를 수정했을 때 입력이 영향을 받지 않는지를 확인한다.

힌트: dict(base)나 base.copy()는 얕은 복사다. 어느 단계에서 깊은 복사가 필요한지 생각한다.