매직 메서드(Magic Method)는 스페셜 메서드라고도 불리며,
메서드 양쪽에 언더스코어(__) 두개로 감싼 형태를 가지고 있다.
매직 메서드는 클래스 내부에서 특별한 기능을 수행할 수 있으며,
Python의 내장 기능과 상호작용할 때 호출된다.
주요 매직 메서드
- __str__()
- __repr__()
- __getitem__()
- __setiten__()
- __delitem__()
- __call__()
- __len__()
- __wnter__()
- __exit__()
1. 객체를 출력하는 매직 메서드
1_1) __str__()
__str__()는 객체를 사람이 읽기 쉬운 문자열로 표현하기 위해 사용되는 매직 메서드이다.
보통 print나 srt로 객체가 호출될 때 자동으로 실행되며
이 메서드를 클래스에 정의하면
객체를 출력할 때 기본 주소값 대신 원하는 형태로 내용을 보여줄 수 있다.
👎 매직메서드 사용 전
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
apple = Fruit("사과", 10)
print(apple) # 객체의 주소가 나타남(기본기능)
실행결과 ▶

👍 매직메서드 사용 후
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
# object 클래스의 기본 __str__ 메서드를 오버라이딩
# : 주소값 대신 커스텀 문자열 반환
def __str__(self): # str()함수와 연결된 매직메서드
return f"{self.name} {self.quantity}개"
apple = Fruit("사과", 10)
print(apple) # __str__ 호출
print(apple) # str() 생략된것
print(str(apple)) # __str__ 호출
실행결과 ▶

1_2) __repr__()
__repr__()은 객체를 개발자 관점에서 정확하게 표현하는 문자열을 반환해주는 기능을 가지고있다.
가능하다면 객체를 다시 생성할 수 있는 형태의 문자열로 반환하는것을 권장하며,
__str__()은 사람이 읽기 좋은 출력인 반면에,
__repr__()은 객체의 구조와 상태를 명확하게 보여주는 공식적인 표현이다.
💡 __repr__()을 사용하는 이유
출력된 글자를 그대로 복사하여 코드창에 붙여넣기하면
똑같은 객체를 바로 다시 쉽게 만들 수 있기 때문이다.
ex ) apple = Fruit(name='사과', quantity=10)
위 예시는 apple변수에 객체를 생성하여 넣는것이다.
👍 매직메서드 사용
결과가 객체를 만드는 형식의 코드로 출력이 된다. (Fruit(name='사과', quantity=10))
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__ 호출
# __str__을 함께 사용하면 __str__이 먼저 출력됨
실행결과 ▶

2. 제너레이터
제너레이터(generator)는 yield 키워드를 사용하여
값을 한 번에 하나씩 생성하여 반환해주는 반복 객체이다.
함수 형태로 사용하며 간단하게 이터레이터를 만들 수 있는 파이썬의 기능이다.
일반함수처럼 보이긴 하지만 yield를 만나는 순간
값을 반환하면서 실행 상태를 유지하고
다음 호출을 진행할 때 이어서 실행이 되기 때문에
전체 데이터를 한번에 만들지 않아 메모리 효율이 매우 좋다. (필요할때마다 생성하여 사용)
※ range() 함수를 만들 때 제너레이터 방식이 사용되었다.
2_1) 매직메서드와 이터레이터
for문이 내부적으로 나동으로 iter() 함수를 호출한다.
이터레이터는 이터러블로부터 실제로 값을 하나씩 꺼내오는 객체로
__iter__()와 __next__() 메서드를 모두 구현하고 있다.
- __iter__() : 반복을 시작함
- __next__() 값을 하나씩 꺼내고 더이상 꺼낼 값이 없으면 StopIteration을 발생시켜 반복 종료
📌 for문 내부 동작 원리
- counter(이터러블 객체)를 iter()함수에 집어넣어 이터레이터를 만든다.
- 반복하면서 next() 함수로 자동 호출하여 값을 하나씩 꺼내 num 담는다.
- 더 이상 꺼낼 값이 없으면 for문을 스스로 종료한다. (StopIteration)
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)
실행결과 ▶

2_2) 제너레이터 사용 방법
yield는 값을 반환하는 return의 형식을 띄고있으며,
함수 형태를 저장하고 다음 호출을 진행 할 때 이어서 실행할 수 있다.
제너레이터는 자동으로 __iter__ + __next__를 만들어주고있기때문에
즉, yield는 iter()와 next()를 동시에 사용할 수 있도록 만들어주는 키워드이다.
def counter(max):
current = 0
while current < max:
current += 1
yield current # current깂을 기억해줌(yield의 역할) = return의 의미
for num in counter(3):
print(num)
실행결과 ▶

3. 인덱싱 매직 메서드
많은 양의 데이터를 관리할 때 주로 Class로 관리를 하게 되는데
이때 인덱싱 매직메서드는 필수적으로 사용된다.
실제로 데이터분석, 머신러닝, 딥러닝에서 매우 중요한 매직메서드이다.
3_1) __getitem__()
__getitem__()은 객체에서 인덱스나 키를 이용해 값을 조회할 때 호출되는 매직 메서드이다.
이 메서드를 사용하면 사용자 정의 객체도 리스트나 딕셔너리처럼 데이터를 꺼낼 수 있고,
내부적으로는 전달된 인덱스나 키를 기반으로 값을 반환하도록 작성한다.
👎 매직메서드 사용 전 : TypeError 발생
# 인덱싱이 안됨
class MyList:
def __init__(self):
self.data = []
ml = MyList() # 객체 자체가 리스트가 아닌 안에 속성이 리스트임
ml.data = [10, 20, 30]
print(ml[0]) # TypeError → 객체 자체가 리스트가 아니기때문!
실행결과 ▶

👍 매직메서드 사용 후
- ml[0] → __getitem__의 index에 0이 전달됨
- return self.data[index] : 어느녀석에 인덱싱할거야?
- self.data = [] 여기로 가서 0번 인덱스 찾아서 출력
class MyList:
def __init__(self):
self.data = []
def __getitem__(self, index):
# 대괄호([])를 쓸 때 자동 호출됨.
# 어떤 리스트에서 값을 꺼낼지 정하는 역할!
return self.data[index]
ml = MyList()
ml.data = [10, 20, 30] # 빈 상자였던 self.data에 실제 데이터를 채워 넣음
print(ml[0])
실행결과 ▶

3_2) __setitem__()
__setitem__()은 객체에서 인덱스나 키를 이용하여 값을 할당해줄 때 호출되는 매직메서드이다.
obj[index] = value 형태의 코드가 실행되면 자동으로 호출되며
이 메서드를 구현하여 사용자 정의 객체에 값을 저장하거나 수정하는 동작을 할 수 있다.
즉, 전달된 인덱스와 값을 이용해서 내부 데이터를 업데이트하도록 구현하는 역할을 한다.
class MyList:
def __init__(self):
self.data = []
def __setitem__(self, index, value):
self.data[index] = value
ml = MyList()
ml.data = [10, 20, 30]
ml[1] = 99 # __setitem__
print(ml.data) # [10, 99, 30]
실행결과 ▶

3_3) __delitem__()
__delitem__()은 객체에서 인덱스나 키를 이용하여 값을 삭제할 때 호출되는 매직 메서드이다.
del obj[index] 형태의 코드로 실행하여 자동 호출이 가능하며
이 메서드를 사용하여 사용자 정의 객체에서 특정 데이터를 삭제하는 로직을 정의할 수 있다.
작성할땐 전달된 인덱스를 기반으로 내부 데이터를 제거하도록 작성해야한다.
class MyList:
def __init__(self):
self.data = []
def __delitem__(self, index):
del self.data[index]
ml = MyList()
ml.data = [10, 20, 30]
del ml[0] # __delitem__
print(ml.data) # [20, 30]
실행결과 ▶

4. 객체를 함수나 값처럼 사용하는 매직 메서드
4_1) __call__()
__call__()은 객체를 함수처럼 호출할 수 있도록 만들어주는 매직 메서드이다.
클래스 인스턴스가 일반 함수처럼 동작할 수 있으며,
내부 상태를 활용한 연산이나 처리 로직을 간결하게 표현할 수 있다.
아래 코드 예제는 만들어진 객체를 함수처럼 사용하면 10이라는 숫자가 __call__에 들어가 실행된다.
즉, 그냥 함수처럼 만든 객체를 사용할 수 있다는 것이다!
class Multiplier:
# 생성자
def __init__(self, n):
self.n = n
# 매직메소드
def __call__(self, x):
return x * self.n
# 객체생성
m = Multiplier(3)
# 출력
print(m(10)) # 30
실행결과 ▶

4_2) __len__()
__len__()은 객체의 길이를 정의하는 매직 메서드이다.
해당 메서드는 len과 같은 기능을 가지고 있다.
사용자 정의 객체도 리스트나 문자열처럼 길이를 가질 수 있으며,
내부 데이터의 개수를 반환하도록 작성한다.
👎 매직메서드 사용 전 : TypeError 발생
class Basket:
def __init__(self):
self.items = []
b = Basket()
b.items = ["사과", "바나나", "오렌지"]
# 객체자체는 갯수를 셀 수 없음
print(len(b))
실행결과 ▶

👍 매직메서드 사용 후
class Basket:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
b = Basket()
b.items = ["사과", "바나나", "오렌지"]
print(len(b)) # 3
실행결과 ▶

5. with문과 함께 사용하는 매직 메서드
with문은 파일, 네트워크, DB연결처럼 사용한 후에 반드시 정리(clean-up)가 필요한 자원을 안전하게 관리하기 위한 문법이다.
블록이 시작될 때 필요한 작업을 수행하고 종료될 때 자동으로 정리 작업을 실행하며,
이를 통해 try-finally를 직접 작성하지 않아도 되고,
예외가 발생하더라도 자원지 정상적으로 해제되도록 보장할 수 있다.
즉, 우리가 알아서 열고닫고할땐 안쓰더라도 큰 상관은 없지만
with문을 사용하면 굳이 닫는 행위를 하지 않아도 되기 때문에 깔끔하게 관리할 수 있다.
그리고 에러가 나더라도 자원이 알아서 삭제되도록 도와주는 기능도 가지고있다.
- 내가 하는 것 : 파일 열기, 수정(준비와 작업)
- with문이 알아서 하는 것 : 열기 도우미(enter), 자동 닫기(exit)
5_1) __enter__()
__enter__()는 with문에 진입할 때 자동으로 호출되는 매직 메서드이다.
자원을 준비하거나 초기화하는 역할을 하며
해당 메서드에서 반환한 값은 as(별칭)뒤의 변수에 할당되러 with블록 내부에서 사용할 수 있다.
5_2) __exit__()
__exit__()는 with블록이 끝날 때 자동으로 호출되는 매직 메서드이다.
사용한 자원을 정리(clean-up)하는 역할을 하며,
해당 메서드는 예외 발생 여부와 관계없이 반드시 실행되게 된다.
만약 예외가 발생할 경우 예외 타입, 값, traceback 정보를 인자로 받아 처리할 수 있다.
👍 기본 사용
class MyResource:
# width문 시작 시 자동 실행 메서드
def __enter__(self):
print("자원 열기")
return self # 리턴된 자원(self)이 as뒤 res 변수로 들어감
# width문 블록 빠져나갈 때 자동실행 메서드(자원정리)
# 코드가 정상종료, 중간에러가 나더라더 무조건 실행
def __exit__(self, exc_type, exc_value, traceback):
print("자원 정리")
# width문이 시작되면 __enter__ 실행
with MyResource() as res:
print("자원 사용 중") # 내가 하고싶은 작업
# 이 자리를 벗어나는 순간 내부적으로 __exit__가 실행되어 자동으로 뒷정리가 됨
실행결과 ▶

👍 에러가 발생하더라도 exit()가 실행되는 예제
print 작업중까지만 작성하고 종료되는게 아닌(에러로 인해)
with문을 다 실행하고(필요한것들 저장하고) 끝낸다.
[핵심 원리 주석]
에러가 발생해서 원래라면 프로그램이 즉시 멈춰야 하지만,
with문 덕분에 튕겨 나가기 직전 __exit__ 구문을 '무조건' 들러서 자원 정리를 마친 뒤 종료된다.
(덕분에 에러가 나도 열려있던 파일이나 자원이 안전하게 닫힘!)
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 # 에러 발생
실행결과 ▶ 모든 작업을 마치고 에러가 나옴

'Python > 기초' 카테고리의 다른 글
| 파이썬 패키지와 모듈 (모듈 생성, 모듈 가져오기, 모듈 설치, 패키지 생성, 패키지 사용하기) (1) | 2026.06.01 |
|---|---|
| 파이썬 객체지향 프로그래밍(OOP) 4대 패러다임 정리 캡슐화, 상속, 다형성, 다형성, 추상화 쉽게 이해하기 (0) | 2026.06.01 |
| 파이썬 객체지향 프로그래밍 핵심 개념 정리(클래스와 메서드) (0) | 2026.05.28 |
| 파이썬 함수 심화 (변수 범위, 클로저, 콜백, 람다) (0) | 2026.05.28 |
| 파이썬 함수 이해하기 (개념과 동작 방식 정리) (1) | 2026.05.27 |