🔁 Iterable 객체

  • 내부에 여러 요소를 가지고 있으며, 한 번에 하나씩 꺼낼 수 있는 반복(iteration) 가능한 객체입니다.
  • 리스트, 문자열, 집합(Set), 딕셔너리 등이 대표적인 이터러블 객체입니다.
  • 파이썬의 for문과 같은 반복문에서 활용 가능합니다.

✨ 특징

  • 반복 가능: for문 등에서 사용할 수 있습니다.
  • 프로토콜 만족:
    • __iter__() 메서드를 가지고 있으며, 이 메서드는 이터레이터(iterator) 객체를 반환합니다.
    • 이터레이터는 __next__() 메서드를 통해 요소를 하나씩 반환합니다.

🔎 iterable vs iterator

구분 iterable(이터러블) iterator(이터레이터)
정의 반복 가능한 객체 실제로 반복을 수행하는 객체
예시 리스트, 문자열, 집합, 딕셔너리 등 iter()의 결과, 리스트의 이터레이터 등
필수 메서드 __iter__() __iter__(), __next__()
사용 목적 반복문에 전달되어 반복을 시작함 반복문 내부에서 실제 값을 차례로 반환함

🛠️ 직접 iterator 만들기

class CountUpTo:
    def __init__(self, max):
        self.max = max
        self.current = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current > self.max:
            raise StopIteration
        self.current += 1
        return self.current - 1

# 사용 예시
counter = CountUpTo(5)
for number in counter:
    print(number)

참고: __init__ 메서드의 오타를 수정했습니다.


📝 Docstring

  • 모듈, 함수, 클래스, 메서드의 정의 바로 아래에 위치하는 설명 문자열입니다.
  • 코드 블록의 용도, 사용법, 동작 방식 등을 문서화하는 데 사용됩니다.
  • __doc__ 속성으로 접근하거나 help() 함수로 확인할 수 있습니다.

✏️ 작성법

  • 모듈: 파일의 맨 위에 작성합니다.
  • 클래스/함수/메서드: 선언 직후, """ (큰따옴표 3개)를 사용하여 작성합니다.
def add(a, b):
    """
    두 숫자를 더한 값을 반환합니다.

    Args:
        a (int): 첫 번째 숫자
        b (int): 두 번째 숫자

    Returns:
        int: 두 숫자의 합
    """
    return a + b

💡 특징 & 활용

  • 코드의 사용법, 인자, 반환값, 발생 가능한 예외 등을 설명할 수 있습니다.
  • Sphinx와 같은 자동 문서화 도구에서 활용됩니다.
  • 코드의 유지보수, 협업, 재사용성을 향상시킵니다.

🛠️ Destructive & Undestructive Function

⚠️ Destructive function (파괴적 함수)

  • 입력 객체(특히 mutable 객체)의 내부 상태를 직접 변경하는 함수입니다.
  • 예시: 리스트의 append(), sort() 메서드 등.
def destructive_append(lst, item):
    lst.append(item) # 원본 리스트가 직접 변경됨

🟢 Undestructive function (비파괴적 함수)

  • 입력 객체를 변경하지 않고, 새로운 객체를 반환하는 함수입니다.
  • 예시: sorted() 함수, + 연산자 등.
def undestructive_append(lst, item):
    return lst + [item] # 새로운 리스트를 반환하며, 원본은 그대로 유지됨
구분 Destructive function Undestructive function
원본 객체 변화 변경됨 변경되지 않음
반환 값 보통 None 또는 변경된 객체 자신 보통 새로운 객체
예시 list.append(), list.sort() sorted(), + 연산
사용 목적 메모리 절약, 객체 상태의 직접 수정 안전성, 데이터의 불변성 유지

🌟 가변 인자: *args, **kwargs

  • 함수의 인자 개수나 형식을 유연하게 처리하기 위해 사용됩니다.
  • 대표적으로 *args**kwargs가 있습니다.

*args

  • 여러 개의 위치 인자(positional arguments)를 하나의 튜플(tuple)로 묶어서 받습니다.
def print_args(*args):
    for arg in args:
        print(arg)

print_args(1, 2, 3) # 1, 2, 3이 차례로 출력됨

**kwargs

  • 여러 개의 키워드 인자(keyword arguments)를 하나의 딕셔너리(dict)로 묶어서 받습니다.
def print_kwargs(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_kwargs(name="Alice", age=30)
# name: Alice
# age: 30

*args와 **kwargs 함께 쓰기

  • 함수 정의 시, 항상 *args**kwargs보다 먼저 와야 합니다.
구분 역할 함수 내 자료형
*args 위치 인자를 튜플로 받음 tuple
**kwargs 키워드 인자를 딕셔너리로 받음 dict

🪄 Decorator

  • 기존 함수나 메서드의 코드를 직접 수정하지 않고, 기능을 확장하거나 변경할 때 사용하는 문법입니다.
  • @데코레이터이름 형태로 함수 선언부 위에 붙여서 사용합니다.
  • 다른 함수를 인자로 받아 새로운 함수를 반환하는 고차 함수(Higher-Order Function)입니다.

🏗️ 기본 사용법

def my_decorator(func):
    def wrapper():
        print("함수 실행 전")
        func()
        print("함수 실행 후")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

# 출력:
# 함수 실행 전
# Hello!
# 함수 실행 후

💡 활용 예시

  • 로깅(Logging): 함수 호출 기록을 남깁니다.
  • 실행 시간 측정: 함수의 실행 시간을 계산합니다.
  • 입력값 검증: 함수에 전달되는 인자의 유효성을 검사합니다.
  • 접근 권한 제어: 특정 사용자만 함수를 실행할 수 있도록 제어합니다.

📝 참고

  • 데코레이터를 사용할 때 원본 함수의 메타 정보(이름, 독스트링 등)를 보존하기 위해 functools.wraps를 사용하는 것이 좋습니다.
  • 여러 개의 데코레이터를 중첩하여 적용할 수 있습니다.