2026/01/05 - 이터레이터, 제너레이터

Soogyung Gwon·2026년 1월 7일

구름을잡아라

목록 보기
4/60

모듈

모듈은 .py 그 자체
모듈은 변수, 함수, 클래스가 포함

모듈 파일의 예)

var = 10

def myfunc():
  print("hello")

모듈 임포트 할때:

import mymod

print(mymod.var)
mymod.myfunc()

mymod 에 점을 찍으면 해당 모듈에 있는 변수, 함수, 클래스에 접근 가능

모듈 import 방법
1) import tkinter(티케이인터)

import tikinter
tkinter.widget = tkinter.Label(None, text='I love Python!')
tkinter.widget.pack();

모듈만 불러오면 모듈 내 변수를 사용하기 위해서는 모듈.변수 형식으로 사용해야 함

2) import *

from tkinter import *
widget = Label(None, text='I love Phthon!')
widget.pack()
Label = 'This is a Label'
from tkinter import *
Label
<class 'tkinter.Label'>

모듈 안의 변수와 기존 변수의 충돌이 발생할 수 있으므로 주의!

실습:
캘린더 모듈에서 윤년 leap 이 포함된 아이템 찾아보기

import calendar

[x for x in dir(calendar) if 'leap' in x]

['isleap', 'leapdays']

주어진 해가 윤년인지 아닌지 판별하는 함수의 사용법

import calendar

try:
    when = int(input("Give me a year: "))
    print(f"윤년이면 True 아니면 False - {calendar.isleap(when)}")
except ValueError:
    print("연도는 숫자로 입력해주세요.")

random 모듈

1 이상 1 미만의 숫자 중에서 아무 숫자나 하나 뽑아서 반환

import random
random.random()

random 모듈의 randrange() 함수

random.randrange(1, 7)

1이상 7미만의 난수

문서에서 random.randrange(start, stop[, step])

stop[, 라 써있는 이유
선택적 인자를 표현하는 방법
즉 아래 둘 가 가능:
random.randrange(start, stop)
random.randrange(start, stop, step)

random 모듈의 shuffle() 함수

abc = ['a', 'b', 'c', 'd', 'e']
random.shuffle(abc)
print(abc)

랜덤 이름 출력하기

import random
color = ['Blue', 'Yellow', 'Red']
snack = ['Latte', 'Saewuchip', 'Satang']
random.shuffle(color)
random.shuffle(snack)
print(f"{color[0]} {snack[0]}")

패키지

패키지는 여러가지 파이썬 파일이 모인 것

기본적인 구조

pymode
	example
    pymode
    	core
    		__init__.py
            core.py
        __init__.py    
        a.py
        b.py
    setup.py

디렉토리 구조를 절대 경로 형태로 적어주는 것이 좋음
pymode.core 디렉토리에 __init__.py파일이 꼭 있어야함

__init__.py 파일이 필요한 이유

Python 3.3 이후에는 “패키지로 인식되기 위해서”는 필수는 아니다. 하지만 실무·설계·제어 관점에서는 여전히 거의 필수다.

이전에는 디렉터리를 패키지로 인식시키는 유일한 방법이었음.
하지만 3.3 이후에는 namespace package가 등장, 그래도 아래와 같은 이유로 필요:

  • 패키지 초기화 코드 실행
  • 패키지의 "공식 API" 정의
  • import 경로 안정성
  • 상대 import 사용 가능
  • 도구/프레임 워크 호환성

__init__.py는 “패키지의 진입점 + 인터페이스 + 제어 장치

서브패키지 구조 (예)

mypackage/
│
├─ __init__.py
│
├─ utils/
│   ├─ __init__.py
│   ├─ file.py
│   └─ math.py
│
├─ core/
│   ├─ __init__.py
│   └─ engine.py
│
└─ main.py

subprocess 개념

서브프로세스의 의미 (서브프로세스가 데이터의 흐름을 조작하는 예시)

  • 새로운 프로세스를 실행하기 위해 도와주고, 프로세서의 입출력/에러결과에 대한 리턴코드를 유저가 직접 제어할 수 있게 하는 것
    예) 쉘 결과를 파일로 저장하기
import subprocess

output = subprocess.check_output("tasklist")
data = output.decode('cp949')
lines = data.splitlines()

for line in lines:
  print(line)

tasklist - 윈도우 명령어
cp949 - 윈도우 인코딩

콜랍(리눅스)용:

import subprocess

output = subprocess.check_output(["ps", "-ef"])
data = output.decode("utf-8")
lines = data.splitlines()

for line in lines:
    print(line)

이터러블(iterable)

리스트, 튜플, 딕셔더리와 같은 기본 자료구조는 for이나 while 문을 사용해서 반복할 수 있음. 이처럼 파이썬에서 반복문을 사용할 수 있는 객체를 이터러블 하다고 함.

iter() 내장 함수에 인자로 전달하면 이터러블한가 알 수 있음

iterator

Iterator란 __next__()를 가지고 있어서
한 번에 하나씩 값을 “소모하며” 꺼낼 수 있는 객체
끝나면 StopIteration 발생

구분				Iterable		Iterator
__iter__()		있음				있음
__next__()		없음				있음
반복 가능 횟수		여러 번			한 번만
상태(state)		없음				있음

이터레이터 객체를 만들때는 __iter____next__ 메소드를 구현해야함

class Season:
  def __init__(self):
    self.data = ["봄", "여름", "가을", "겨울"]
    self.index = 0
  
  def __iter__(self):
    return self

  def __next__(self):
    if self.index < len(self.data):
      cur_season = self.data[self.index]
      self.index += 1
      return cur_season
    else:
      raise StopIteration

s = Season()
for i in s:
  print(i)
  
봄
여름
가을
겨울

map()

반복 가능한 iterable 객체를 받아서, 각 요소에 함수를 적용해주는 함수.

map(function, iterable, /, *iterables, strict=False)

def add_1(n):
  return n + 1

target = [1, 2, 3, 4, 5]
result = []

for value in target:
  result.append(add_1(value))

print(result)

위의 코드를 map을 사용하여 바꾸면:

print(list(map(add_1, target)))

함수 add_1가 재사용의 목적이 없다면 lambda 함수를 적용하는 것이 좋음
-> 다른 곳에서 쓰이지 않고 오직 이 map을 위해서 존재한다면 이름이 있는 함수로 따로 정의할 필요가 없음

def add_1(n):
  return n + 1

target = [1, 2, 3, 4, 5]
result = []

print(list(map(add_1, target)))

result = list(map(lambda n: n + 1, target))
print(result)
  • map은 객체를 반환하므로 list()로 감싸야 함

리스트 안에 있는 값들을 str 타입으로 변경하는 예제)

target = [1, 2, 3, 4, 5]
map(str, target)

filter()

filter 함수는 특정 조건으로 걸러서 걸러진 요소들롤 iterator 객체를 만들어서 리턴

map 함수와 사용 방법은 동일하나, 함수의 결과가 참인지 거짓인지에 따라 해당 요소를 포함할지 결정

filter(function, iterable, /)

target = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = []

def is_even(n):
  return True if n % 2 == 0 else False

for value in target:
  if is_even(value):
    result.append(value)

print(result)

위의 코드를 filter()를 사용하여 바꾸면:

target2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def is_even2(n):
  return True if n % 2 == 0 else False

result2 = filter(is_even2, target2)

print(list(result2))

람다를 사용하는 경우:

target3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

result3 = filter(lambda x : x%2==0, target3)
print(list(result3))

generator

  • 제너레이터는 지연평가(Lazy Evaluation) 구현체

  • 지연평가 - 평가를 늦추고 필요할 때 값을 계산해 주는 객체

  • Lazy 한 객체들은 많은 정보를 가지고 있는 상황에서 메모리상에 많은 이득을 가져다 줍니다.

  • 파이썬에서 모든 Lazy Evaluation 은 이터레이터라고 불림
    그리고 이런 이터레이터 중에서 특정 방식을 통해서 생성한 iterator를 generator라고 구분해서 부름

  • return 키워드 대신 yield라는 키워드를 사용

  • return은 결과값을 주고 함수도 끝, yield 키워드는 결과값을 돌려주지만 실행 상태 그대로 저장해 두고 멈춤

def num_gen():
  for i in range(3):
    yield i

g = num_gen() # 제너레이터 객체 생성

print(g, type(g))

for i in g:
  print(i)

<generator object num_gen at 0x7bf6b9fb6980> <class 'generator'>
0
1
2
  • 작은 데이터에서는 잘 동작하는 프로그램이 큰 규모의 데이터넷에서는 제대로 동작하지 않거나 매우 느리게 동작하게 됨
  • 제너레이터를 사용하면 한 번에 데이터를 모아서 처리하지 않기 때문에 큰 메모리를 사용하지 않아도 됨
  • 제너레이터는 큰 규모의 확장성이 있는 프로그램을 개발하기 위해 사용함
profile
오랜시간 망설였던 코딩을 다시 해보려고 노력하고 있는 사람

0개의 댓글