Launguage

Python 매직 메서드 완벽 가이드

Somaz 2025. 11. 7. 00:00
728x90
반응형

Overview

매직 메서드(Magic Methods)는 Python 클래스에 특별한 기능을 부여하는 메서드다. ` __init__`, `__str__`  처럼 앞뒤로 언더스코어 두 개(__)가 붙어서 던더(Dunder) 메서드라고도 불린다.

 

매직 메서드를 사용하면 클래스가 Python의 내장 함수나 연산자와 자연스럽게 동작하게 만들 수 있다.

 

 

 

 


 

 

1. 객체 생성과 초기화

 

`__init__`: 생성자

가장 많이 사용하는 매직 메서드로, 객체가 생성될 때 자동으로 호출된다.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print(f"{name} 객체가 생성되었습니다!")

person = Person("철수", 25)
# 출력: 철수 객체가 생성되었습니다!

 

 

`__new__`: 인스턴스 생성

`__init__` 보다 먼저 호출되며, 실제로 객체를 생성하는 메서드다. 싱글톤 패턴 등에서 사용된다.

class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # True - 같은 객체!

 

 

 

2. 문자열 표현

 

 

`__str__`: 사용자 친화적 문자열

`print()` 함수나 `str()` 로 객체를 출력할 때 사용된다.

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author
    
    def __str__(self):
        return f"'{self.title}' by {self.author}"

book = Book("파이썬 완벽 가이드", "홍길동")
print(book)  # '파이썬 완벽 가이드' by 홍길동

 

`__repr__`: 개발자용 문자열

디버깅할 때 유용하며, `repr()` 함수나 인터프리터에서 객체를 직접 입력했을 때 사용된다.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"
    
    def __str__(self):
        return f"({self.x}, {self.y})"

point = Point(3, 4)
print(point)        # (3, 4) - __str__ 사용
print(repr(point))  # Point(x=3, y=4) - __repr__ 사용

차이점: `__str__` 은 일반 사용자용, `__repr__` 은 개발자용으로 더 자세한 정보를 담는다.

 

 

 

 

 

3. 비교 연산자

 

 

모든 비교 연산자 구현하기

class Money:
    def __init__(self, amount):
        self.amount = amount
    
    def __eq__(self, other):
        """=="""
        return self.amount == other.amount
    
    def __ne__(self, other):
        """!="""
        return self.amount != other.amount
    
    def __lt__(self, other):
        """<"""
        return self.amount < other.amount
    
    def __le__(self, other):
        """<="""
        return self.amount <= other.amount
    
    def __gt__(self, other):
        """>"""
        return self.amount > other.amount
    
    def __ge__(self, other):
        """>="""
        return self.amount >= other.amount

money1 = Money(1000)
money2 = Money(2000)

print(money1 < money2)   # True
print(money1 == money2)  # False
print(money1 >= money2)  # False

 

 

: `functools.total_ordering` 데코레이터를 사용하면 `__eq__` 와 `__lt__` 만 구현해도 나머지가 자동 생성된다!

from functools import total_ordering

@total_ordering
class Money:
    def __init__(self, amount):
        self.amount = amount
    
    def __eq__(self, other):
        return self.amount == other.amount
    
    def __lt__(self, other):
        return self.amount < other.amount
    
    # 이제 >, <=, >= 도 자동으로 사용 가능!

 

 

4. 산술 연산자

 

기본 산술 연산

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        """+"""
        return Vector(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        """-"""
        return Vector(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        """*"""
        return Vector(self.x * scalar, self.y * scalar)
    
    def __truediv__(self, scalar):
        """/"""
        return Vector(self.x / scalar, self.y / scalar)
    
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(2, 3)
v2 = Vector(1, 1)

print(v1 + v2)      # Vector(3, 4)
print(v1 - v2)      # Vector(1, 2)
print(v1 * 2)       # Vector(4, 6)
print(v1 / 2)       # Vector(1.0, 1.5)

 

 

복합 할당 연산자

class Counter:
    def __init__(self, value=0):
        self.value = value
    
    def __iadd__(self, other):
        """+="""
        self.value += other
        return self
    
    def __isub__(self, other):
        """-="""
        self.value -= other
        return self

counter = Counter(10)
counter += 5
print(counter.value)  # 15
counter -= 3
print(counter.value)  # 12

 

 

5. 컨테이너 매직 메서드

 

 

리스트처럼 동작하는 클래스 만들기

class CustomList:
    def __init__(self):
        self._items = []
    
    def __len__(self):
        """len() 함수"""
        return len(self._items)
    
    def __getitem__(self, index):
        """obj[index]"""
        return self._items[index]
    
    def __setitem__(self, index, value):
        """obj[index] = value"""
        self._items[index] = value
    
    def __delitem__(self, index):
        """del obj[index]"""
        del self._items[index]
    
    def __contains__(self, item):
        """item in obj"""
        return item in self._items
    
    def append(self, item):
        self._items.append(item)

my_list = CustomList()
my_list.append(1)
my_list.append(2)
my_list.append(3)

print(len(my_list))        # 3
print(my_list[0])          # 1
print(2 in my_list)        # True
my_list[1] = 10
print(my_list[1])          # 10

 

 

6. 호출 가능한 객체

 

 

`__call__`: 객체를 함수처럼 호출

class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    
    def __call__(self, x):
        return x * self.factor

double = Multiplier(2)
triple = Multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

# 객체를 함수처럼 사용 가능!

 

 

 

실전 예제: 데코레이터를 클래스로 구현

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
    
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} 호출 횟수: {self.count}")
        return self.func(*args, **kwargs)

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

say_hello()  # say_hello 호출 횟수: 1, Hello!
say_hello()  # say_hello 호출 횟수: 2, Hello!
say_hello()  # say_hello 호출 횟수: 3, Hello!

 

 

7. 컨텍스트 매니저

 

 

`__enter__` 와 `__exit__: with `문 지원

class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None
    
    def __enter__(self):
        print(f"파일 열기: {self.filename}")
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("파일 닫기")
        if self.file:
            self.file.close()

# with 문과 함께 사용
with FileManager('test.txt', 'w') as f:
    f.write("Hello, World!")
# 자동으로 파일이 닫힘!

 

 

8. 실전 예제: 좌표 클래스

 

모든 개념을 활용한 완전한 예제다.

from functools import total_ordering
import math

@total_ordering
class Point:
    """2D 좌표를 표현하는 클래스"""
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # 문자열 표현
    def __str__(self):
        return f"({self.x}, {self.y})"
    
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"
    
    # 비교 연산
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __lt__(self, other):
        # 원점으로부터의 거리로 비교
        return self.distance_from_origin() < other.distance_from_origin()
    
    # 산술 연산
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Point(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Point(self.x * scalar, self.y * scalar)
    
    # 기타 유용한 메서드
    def __abs__(self):
        """abs(point) - 원점으로부터의 거리"""
        return self.distance_from_origin()
    
    def __bool__(self):
        """bool(point) - 원점이 아니면 True"""
        return self.x != 0 or self.y != 0
    
    def distance_from_origin(self):
        return math.sqrt(self.x**2 + self.y**2)

# 사용 예시
p1 = Point(3, 4)
p2 = Point(1, 2)

print(p1)                    # (3, 4)
print(repr(p1))              # Point(x=3, y=4)
print(p1 + p2)               # (4, 6)
print(p1 - p2)               # (2, 2)
print(p1 * 2)                # (6, 8)
print(p1 == p2)              # False
print(p1 > p2)               # True
print(abs(p1))               # 5.0
print(bool(Point(0, 0)))     # False
print(bool(p1))              # True

 

 

 

주요 매직 메서드 정리

카테고리 메서드 설명
생성/소멸 `__init__` 객체 초기화
  `__new__` 객체 생성
  `__del__` 객체 소멸 시
문자열 `__str__` str(), print()
  `__repr__` repr(), 인터프리터
비교 `__eq__` ==
  `__ne__` !=
  `__lt__` <
  `__le_` <=
  `__gt__` >
  `__ge__` >=
산술 `__add__` +
  `__sub__` -
  `__mul__` *
  `__truediv__` /
  `__floordiv__` //
  `__mod__` %
  `__pow__` **
컨테이너 `__len__` len()
  `__getitem__` obj[key]
  `__setitem__` obj[key] = val
  `__delitem__` del obj[key]
  `__contains__` item in obj
기타 `__call__` obj()
  `__enter__` with 문 진입
  `__exit__` with 문 종료
  `__bool__` bool()
  `__hash__` hash()

 

 

 

 


 

 

 

결론

매직 메서드를 활용하면

  • 클래스를 Python의 내장 타입처럼 자연스럽게 사용 가능
  • 연산자 오버로딩으로 직관적인 코드 작성
  • 더 Pythonic하고 읽기 쉬운 코드
  • 강력한 추상화와 캡슐화

 

 

매직 메서드는 Python의 객체지향 프로그래밍을 한 단계 업그레이드시켜주는 핵심 기능이다!

 

 

 

 

 

 

 

 


Reference

튜토리얼 & 가이드

728x90
반응형