파이썬 클래스의 출력 결과가 낯설고 이해하기 어렵게 느껴졌다면, __str__ 메서드를 아직 제대로 활용하지 않았을 가능성이 있다. 이 글에서는 __str__이 어떤 역할을 하는지, 어떻게 사용하면 객체를 더 직관적으로 출력할 수 있는지 정리해보았다.
__str__ 메서드 이해하기
__str__ 메서드란?
__str__은 파이썬에서 객체를 사람이 읽기 쉬운 문자열 형태로 표현하기 위해 사용하는 특별한 메서드다. 보통 print() 함수나 str() 함수를 사용할 때 자동으로 호출된다.
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return f'이름: {self.name}'
p = Person("철수")
print(p) # 출력: 이름: 철수
print(str(p)) # 출력: 이름: 철수
__str__ 메서드는 객체를 print()나 str()로 출력할 때 사람이 읽기 쉬운 문자열을 반환하도록 정의하는 특수 메서드다.
기본 타입에서의 동작
파이썬의 기본 자료형도 모두 __str__ 메서드를 가지고 있다.
print(str(123)) # '123'
print(str(True)) # 'True'
print(str([1, 2, 3])) # '[1, 2, 3]'
- 숫자 → 문자열 숫자
- 불린값 → 'True' 또는 'False'
- 리스트, 딕셔너리 등 → 사람이 알아보기 쉬운 구조 문자열
이는 내부적으로 해당 타입의 __str__ 메서드가 정의돼 있기 때문이다.
사용자 정의 클래스에서의 동작
사용자 정의 클래스는 기본적으로 __str__ 메서드가 정의돼 있지 않기 때문에, 출력하면 이런 식으로 보인다.
class Product:
def __init__(self, name):
self.name = name
item = Product("노트북")
print(item) # <__main__.Product object at 0x10abcf>
보기 불편한 메모리 주소 형태의 문자열이 출력된다.
해결 방법
class Product:
def __init__(self, name):
self.name = name
def __str__(self):
return f'상품명: {self.name}'
item = Product("노트북")
print(item) # 상품명: 노트북
클래스를 읽기 좋게 만들기
객체를 출력할 때 의미 없는 메모리 주소 대신, 사람이 읽기 좋은 정보를 보여주면 훨씬 더 직관적인 코드를 만들 수 있다. 이때 사용하는 것이 바로 __str__ 메서드다.
예제 코드 (Person 클래스)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
__str__ 없이 출력
p = Person("영희", 29)
print(p)
# 출력: <__main__.Person object at 0x1043...>
__str__ 추가 후 출력
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name} ({self.age}세)'
p = Person("영희", 29)
print(p)
# 출력: 영희 (29세)
Person 클래스는 이름과 나이를 저장하는 객체를 만들 수 있도록 설계되어 있으며, __str__ 메서드를 정의해 객체를 출력할 때 "영희 (29세)"처럼 사람이 읽기 쉬운 형식의 문자열이 보이도록 한다. print(p)를 호출하면 내부적으로 str(p)가 실행되고, 이는 곧 p.__str__()을 호출하게 되어 "영희 (29세)"라는 결과가 출력된다.
예제 코드 (Product 클래스)
class Product:
def __init__(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
def __str__(self):
return f'{self.name} - {self.price}원 (재고: {self.stock}개)'
item = Product("무선 이어폰", 79000, 12)
print(item)
# 출력: 무선 이어폰 - 79000원 (재고: 12개)
__init__ 메서드는 객체가 생성될 때 이름(name), 가격(price), 재고(stock) 정보를 받아 해당 속성에 저장하고, __str__ 메서드는 이 정보를 "무선 이어폰 - 79000원 (재고: 12개)"와 같은 형태로 보기 쉽게 출력할 수 있도록 문자열을 반환한다.
item = Product("무선 이어폰", 79000, 12)와 같이 객체를 생성하고 print(item)을 호출하면 내부적으로 item.__str__()이 실행되어 "무선 이어폰 - 79000원 (재고: 12개)"라는 결과가 출력된다.
예제 코드 (Transaction 클래스)
class Transaction:
def __init__(self, from_account, to_account, amount):
self.from_account = from_account
self.to_account = to_account
self.amount = amount
def __str__(self):
return f'{self.from_account} → {self.to_account}: {self.amount:,}원'
t = Transaction("계좌1", "계좌2", 1000000)
print(t)
# 출력: 계좌1 → 계좌2: 1,000,000원
Transaction 클래스는 송금 출발 계좌(from_account), 도착 계좌(to_account), 금액(amount)을 저장하는 구조로 되어 있다. 객체가 생성될 때 이 세 가지 정보를 받아 각각의 속성에 저장하며, __str__ 메서드는 이 정보를 "계좌1 → 계좌2: 1,000,000원"처럼 직관적으로 보여주는 문자열을 반환한다.
예를 들어, t = Transaction("계좌1", "계좌2", 1000000)처럼 객체를 만들고 print(t)를 호출하면, 내부적으로 t.__str__()이 실행되어 "계좌1 → 계좌2: 1,000,000원"이라는 결과가 출력된다. 여기서 :,는 숫자를 천 단위로 쉼표 구분해 가독성을 높이기 위한 포맷팅이다.
디버깅과 로깅
코드를 개발하다 보면 버그를 찾거나, 프로그램의 상태를 확인하기 위해 디버깅이나 로깅을 자주 하게 된다. 이때 객체가 어떤 값들을 가지고 있는지 확인하려면 __str__ 메서드의 역할이 중요하게 작용한다.
로깅에서 __str__의 역할
다음과 같이 로그를 출력할 때, 객체를 직접 넣으면 __str__의 반환값이 문자열로 자동 사용된다.
import logging
class User:
def __init__(self, username, role):
self.username = username
self.role = role
def __str__(self):
return f'User({self.username}, {self.role})'
user = User("admin", "관리자")
logging.info(f"접속한 사용자: {user}")
__str__을 정의하지 않았다면 로그에 의미 없는 <__main__.User object at 0x...> 같은 문자열이 출력되지만, 커스터마이징을 해두면 "접속한 사용자: User(admin, 관리자)"처럼 직관적인 메시지를 확인할 수 있다.
클래스 내부 상태 출력
클래스 내부 데이터를 디버깅할 때, 다음과 같은 방식으로 __str__을 작성해두면 상태 확인이 쉬워진다.
class Order:
def __init__(self, id, items, total_price):
self.id = id
self.items = items
self.total_price = total_price
def __str__(self):
return f'Order #{self.id}: {len(self.items)}개 상품, 총 {self.total_price:,}원'
order = Order(1023, ['마우스', '키보드', '모니터'], 195000)
print(order)
# 출력: Order #1023: 3개 상품, 총 195,000원
- 리스트나 숫자 데이터를 요약해서 보여주면 로그나 디버깅 중에도 객체 상태를 한눈에 파악할 수 있다.
- 포맷팅도 적극적으로 활용해 가독성을 높이는 것이 좋다.
logging + __str__ = 읽기 쉬운 로그
실제 로그 파일에 남는 출력도 더 깔끔해지고, 운영 중인 서비스에서 객체 상태를 파악할 때 큰 도움이 된다.
logging.debug(f"[주문 확인] {order}")
# 로그 예시: [주문 확인] Order #1023: 3개 상품, 총 195,000원
__str__는 사람이 읽기 쉬운 형태를, __repr__는 개발자용 디버깅 정보를 담는 것이 일반적인 관례다.
def __repr__(self):
return f'Order(id={self.id}, items={self.items}, total_price={self.total_price})'
요약
- __str__을 잘 작성해두면 print나 logging 시 객체 상태를 한눈에 파악할 수 있어 디버깅과 로깅이 훨씬 수월해진다.
- 실제 운영 환경에서도 문제를 빠르게 추적할 수 있는 강력한 도구가 된다.
- 가독성 높은 포맷과 핵심 정보만 담는 것이 중요하다.
마무리
__str__ 메서드는 단순한 출력용 도구가 아니다. 객체가 어떤 의미를 갖고 있는지, 어떤 정보를 담고 있는지를 사람이 이해하기 쉽게 표현해주는 인터페이스다. 클래스를 설계할 때 __str__을 잘 정의해두면 print()나 로그 출력, 디버깅 과정에서 훨씬 직관적이고 깔끔한 결과를 얻을 수 있다.
'Python > python' 카테고리의 다른 글
| 파이썬 str 타입 중심의 문자열 인코딩과 디코딩 총정리 (2) | 2025.06.18 |
|---|---|
| 파이썬 프로그래밍 필수, def 함수 제대로 쓰기 (1) | 2025.06.03 |
| 파이썬 subprocess.Popen() 함수를 활용하여 프로세스 관리하기 (1) | 2024.01.22 |
| 파이썬을 이용하여 환율 정보 데이터 수집하기 (0) | 2024.01.10 |
| 외부 프로그램 실행, 파이썬 subprocess.run()으로 쉽게 끝내기! (0) | 2023.11.01 |