매직 메소드(또는 dunder 메소드 – 더블 언더스코어에서 유래)는 이름이 두 개의 언더스코어로 시작하고 끝나는 특별한 메소드입니다. 예를 들어, __init__, __str__, __add__와 같습니다. 이들은 사용자 정의 클래스의 인스턴스를 파이썬의 문법과 동작에 통합하게 해 줍니다: 산술 연산, 비교, 문자열 변환, 컬렉션 프로토콜 작업 등을 정의할 수 있습니다.
예제:
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 __str__(self): return f"Vector({self.x}, {self.y})" v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # v1.__add__(v2)가 호출되어 Vector(4, 6)가 반환됩니다.
만약 자신의 클래스에서
__eq__를 구현하지 않으면,==연산자를 사용해 인스턴스를 비교할 때 어떻게 될까요?
답변: 기본적으로 == 연산자는 객체의 동일성(메모리 주소, is 연산자와 유사)을 기준으로객체를 비교합니다. 매직 메소드 __eq__를 오버라이드하지 않는다면요.
class A: pass print(A() == A()) # False, 객체는 "같아 보이지만" 다릅니다.
이야기
그래프 구조를 비교해야 하는 프로젝트에서 __eq__ 메소드를 구현하지 않았습니다. 그 결과 "노드가 이미 추가되었는지"를 확인할 때 잘못된 결과를 초래했습니다. == 연산자가 객체를 id로 비교했기 때문입니다.
이야기
REST API를 작성할 때 객체를 로그에 기록하기 위해 str(obj)를 통해 문자열로 직렬화했으나 __str__을 정의하는 것을 잊었습니다. 그 결과로 출력된 내용은 <MyObj object at 0x...>와 같은 읽기 힘든 텍스트로, 문제 진단이 어렵게 만들었습니다.
이야기
수학 계산을 위한 라이브러리에서 __add__만 구현하고 __iadd__는 잊어버렸습니다. 그 결과 v += w 표현이 기대한 대로 작동하지 않았고 (새 객체가 생성되고 이전 객체가 업데이트되지 않음), 이것이 복잡한 계산에서 메모리 누수로 이어졌습니다.