매직 메서드(magic method)는 파이썬에서 특정 문법이나 연산이 실행될 때 자동으로 호출되는 특별한 메서드로, __len__, __str__, __getitem__처럼 양쪽에 밑줄(__)이 붙는 형태를 가집니다. 이 메서드들을 클래스에 구현하면 len(obj), print(obj), obj[0], obj + obj 같은 파이썬의 기본 문법과 자연스럽게 연결되어 객체의 동작을 직접 정의할 수 있습니다. 즉, 매직 메서드는 객체를 리스트처럼 사용하거나, 연산을 수행하거나, 출력 형태를 바꾸는 등 파이썬의 문법과 객체를 이어주는 핵심 기능입니다.
__str__()는 객체를 사람이 읽기 쉬운 문자열로 표현하기 위해 사용하는 매직 메서드로, print(obj)나 str(obj)가 호출될 때 자동으로 실행됩니다. 이 메서드를 클래스에 정의하면 객체를 출력할 때 기본 주소값 대신 원하는 형태로 내용을 보여줄 수 있어 디버깅이나 사용자 출력에 매우 유용합니다.
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
def __str__(self):
return f"{self.name} {self.quantity}개"
apple = Fruit("사과", 10)
print(apple) # __str__ 호출
print(str(apple)) # __str__ 호출
__repr__()은 객체를 개발자 관점에서 정확하게 표현하는 문자열을 반환하는 매직 메서드로, 주로 디버깅이나 로그에서 사용됩니다. repr(obj)를 호출하거나 인터프리터에서 객체를 직접 평가할 때 자동으로 호출되며, 가능하다면 객체를 다시 생성할 수 있는 형태의 문자열을 반환하는 것이 권장됩니다. __str__()이 사람이 읽기 좋은 출력이라면, __repr__()은 객체의 구조와 상태를 명확하게 보여주는 공식적인 표현입니다.
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
def __repr__(self):
return f"Fruit(name='{self.name}', quantity={self.quantity})"
apple = Fruit("사과", 10)
print(repr(apple)) # __repr__ 호출
print(apple) # __str__ 없으면 __repr__ 호출
제너레이터(generator)는 yield 키워드를 사용해 값을 한 번에 하나씩 생성해 반환하는 반복 객체로, 함수 형태로 간단하게 이터레이터를 만들 수 있는 파이썬의 기능입니다. 일반 함수처럼 보이지만 yield를 만나면 값을 반환하면서도 실행 상태를 유지하고, 다음 호출 시 이어서 실행되기 때문에 전체 데이터를 한 번에 만들지 않고 필요할 때마다 생성할 수 있어 메모리 효율이 매우 높습니다.
class Counter:
def __init__(self, max):
self.max = max
self.current = 0
def __iter__(self):
return self # 자기 자신을 iterator로 사용
def __next__(self):
if self.current < self.max:
self.current += 1
return self.current
else:
raise StopIteration
counter = Counter(3)
for num in counter:
print(num)
👉 for문이 내부적으로 자동으로 iter()를 호출합니다.
👉 이터레이터는 이터러블로부터 실제로 값을 하나씩 꺼내는 객체로, __iter__()와 __next__() 메서드를 모두 구현하고 있습니다. __iter__()는 반복을 시작하게 하고, __next__()는 값을 하나씩 꺼내며, 더 이상 반환할 값이 없으면 StopIteration 예외를 발생시켜 반복을 종료합니다.
def counter(max):
current = 0
while current < max:
current += 1
yield current
for num in counter(3):
print(num)
👉 yield의 의미
1. 값을 반환한다
2. 함수 상태를 저장한다
3. 다음 호출 시 이어서 실행한다
👉 제너레이터는 자동으로 __iter__ + __next__를 만들어줍니다.
__getitem__()은 객체에서 인덱스나 키를 이용해 값을 조회할 때 호출되는 매직 메서드로, obj[index] 또는 obj[key] 형태로 접근하면 자동으로 실행됩니다. 이 메서드를 구현하면 사용자 정의 객체도 리스트나 딕셔너리처럼 데이터를 꺼낼 수 있으며, 내부적으로는 전달된 인덱스나 키를 기반으로 값을 반환하도록 작성하면 됩니다.
__setitem__()은 객체에서 인덱스나 키를 이용해 값을 할당할 때 호출되는 매직 메서드로, obj[index] = value 형태의 코드가 실행되면 자동으로 호출됩니다. 이 메서드를 구현하면 사용자 정의 객체에 값을 저장하거나 수정하는 동작을 제어할 수 있으며, 전달된 인덱스와 값을 이용해 내부 데이터를 업데이트하도록 구현합니다
__delitem__()은 객체에서 인덱스나 키를 이용해 값을 삭제할 때 호출되는 매직 메서드로, del obj[index] 형태의 코드가 실행되면 자동으로 호출됩니다. 이 메서드를 구현하면 사용자 정의 객체에서 특정 데이터를 삭제하는 로직을 정의할 수 있으며, 전달된 인덱스를 기반으로 내부 데이터를 제거하도록 작성합니다
class MyList:
def __init__(self):
self.data = []
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __delitem__(self, index):
del self.data[index]
ml = MyList()
ml.data = [10, 20, 30]
print(ml[0]) # __getitem__ → 10
ml[1] = 99 # __setitem__
print(ml.data) # [10, 99, 30]
del ml[0] # __delitem__
print(ml.data) # [99, 30]
__call__()은 객체를 함수처럼 호출할 수 있게 만들어주는 매직 메서드로, obj() 형태로 객체를 실행하면 자동으로 호출됩니다. 이 메서드를 구현하면 클래스 인스턴스가 일반 함수처럼 동작할 수 있으며, 내부 상태를 활용한 연산이나 처리 로직을 간결하게 표현할 수 있습니다.
class Multiplier:
def __init__(self, n):
self.n = n
def __call__(self, x):
return x * self.n
m = Multiplier(3)
print(m(10)) # 30
__len__()은 객체의 길이를 정의하는 매직 메서드로, len(obj)를 호출할 때 자동으로 실행됩니다. 이 메서드를 구현하면 사용자 정의 객체도 리스트나 문자열처럼 길이를 가질 수 있으며, 내부 데이터의 개수를 반환하도록 작성하면 됩니다.
class Basket:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
b = Basket()
b.items = ["사과", "바나나", "오렌지"]
print(len(b)) # 3
with 문은 파일, 네트워크, DB 연결처럼 사용 후 반드시 정리(clean-up)가 필요한 자원을 안전하게 관리하기 위한 문법으로, 블록이 시작될 때 필요한 작업을 수행하고 종료될 때 자동으로 정리 작업을 실행해줍니다. 이를 통해 try-finally를 직접 작성하지 않아도 되고, 예외가 발생하더라도 자원이 정상적으로 해제되도록 보장할 수 있습니다.
__enter__()는 with 문에 진입할 때 자동으로 호출되는 매직 메서드로, 자원을 준비하거나 초기화하는 역할을 합니다. 이 메서드에서 반환한 값은 as 뒤의 변수에 할당되어 with 블록 내부에서 사용됩니다.
__exit__()는 with 블록이 끝날 때 자동으로 호출되는 매직 메서드로, 사용한 자원을 정리(clean-up)하는 역할을 합니다. 이 메서드는 예외 발생 여부와 관계없이 반드시 실행되며, 예외가 발생한 경우에는 예외 타입, 값, traceback 정보를 인자로 받아 처리할 수 있습니다.
class MyResource:
def __enter__(self):
print("자원 열기")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("자원 정리")
with MyResource() as res:
print("자원 사용 중")
class MyResource:
def __enter__(self):
print("자원 열기")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("자원 정리")
print("예외 타입:", exc_type)
with MyResource():
print("작업 중")
1 / 0 # 에러 발생
👉 에러가 나도 __exit__()는 반드시 실행됩니다.
| 모듈 (1) | 2026.04.30 |
|---|---|
| 예외 처리 (0) | 2026.04.30 |
| 객체지향 프로그래밍 4대 패러다임 (0) | 2026.04.28 |
| 객체지향 프로그래밍(OOP) (0) | 2026.04.27 |
| 사용자 정의 함수 (0) | 2026.04.27 |