
파이썬에서 클래스를 설계할 때 가장 많이 간과하는 부분 중 하나가 바로 역방향 연산자(Reflected/Right Operators)입니다. 단순히 __add__만 정의했다고 해서 우리의 객체가 모든 상황에서 완벽하게 동작하는 것은 아닙니다. 특히 외부 라이브러리의 기본 타입(int, float 등)과 내가 만든 커스텀 객체를 혼합하여 연산할 때 발생하는 'TypeError'를 우아하게 해결하는 열쇠가 바로 __radd__와 같은 메서드에 있습니다. 본 포스팅에서는 파이썬 연산자 오버로딩의 깊은 곳을 탐구하며, 'r' 메서드가 왜 존재하며, 일반 메서드와 어떤 차이가 있는지, 그리고 이를 통해 코드의 견고함을 3배 이상 높이는 구체적인 방법을 제시합니다.
1. 왜 'r'이 붙은 메서드가 필요한가? (문제 인식)
파이썬에서 a + b 연산을 수행할 때, 인터프리터는 다음의 단계를 거칩니다.
- 먼저
a.__add__(b)를 호출하려고 시도합니다. - 만약
a에__add__가 없거나, 호출 결과가NotImplemented를 반환한다면? - 비로소 파이썬은
b.__radd__(a)를 호출합니다.
즉, 왼쪽 피연산자가 해당 연산을 지원하지 않을 때 오른쪽 피연산자가 연산의 주도권을 넘겨받는 메커니즘입니다. 이를 통해 우리는 기본 숫자형과 우리가 만든 객체 간의 위치에 상관없는 자유로운 연산을 구현할 수 있습니다.
2. 일반 메서드 vs 역방향 메서드의 3가지 핵심 차이
단순히 위치의 차이뿐만 아니라, 동작 원리에서 오는 결정적인 차이점이 존재합니다.
| 항목 | 일반 메서드 (__add__, __sub__) | 역방향 메서드 (__radd__, __rsub__) |
|---|---|---|
| 호출 우선순위 | 1순위 (왼쪽 피연산자 기준) | 2순위 (오른쪽 피연산자 기준) |
| 주요 역할 | 객체 본인이 주체가 되는 연산 수행 | 기본 타입이나 타 객체와의 호환성 해결 |
| 구현 필수성 | 기본 연산 기능 구현 시 필수 | 교환 법칙이 성립하거나 확장성이 중요할 때 필수 |
| 반환값 처리 | 실패 시 NotImplemented 반환 | 왼쪽 객체가 모르는 타입일 때 구원 투수 역할 |
3. 정교한 연산을 위한 7가지 역방향 메서드 활용 방법
다음은 실무에서 가장 자주 사용되는 역방향 메서드 리스트와 그 활용 목적입니다.
- __radd__(self, other): 덧셈 연산의 역방향.
10 + MyObject형태 해결. - __rsub__(self, other): 뺄셈 연산의 역방향. 뺄셈은 순서가 중요하므로 내부 로직에서
other - self처리가 핵심. - __rmul__(self, other): 곱셈 연산의 역방향. 스칼라 곱셈 구현 시 필수.
- __rtruediv__(self, other): 나눗셈 연산의 역방향.
100 / MyObject상황 처리. - __rfloordiv__(self, other): 몫 연산(//)의 역방향.
- __rmod__(self, other): 나머지 연산(%)의 역방향.
- __rpow__(self, other): 거듭제곱(**)의 역방향.
4. Sample Example: 화폐(Currency) 클래스 설계
정수와 자유롭게 덧셈과 뺄셈이 가능한 화폐 클래스를 통해 'r' 메서드의 실질적인 방법을 보여드립니다.
class Money:
def __init__(self, amount, currency="KRW"):
self.amount = amount
self.currency = currency
def __repr__(self):
return f"{self.amount} {self.currency}"
# 일반 덧셈: Money + (int 또는 Money)
def __add__(self, other):
if isinstance(other, Money):
return Money(self.amount + other.amount, self.currency)
if isinstance(other, (int, float)):
return Money(self.amount + other, self.currency)
return NotImplemented
# 역방향 덧셈: int + Money
# __add__와 로직이 같으므로 재사용 가능
def __radd__(self, other):
return self.__add__(other)
# 역방향 뺄셈: 1000 - Money(300) -> 700원
def __rsub__(self, other):
if isinstance(other, (int, float)):
return Money(other - self.amount, self.currency)
return NotImplemented
# 테스트 코드
m1 = Money(500)
print(m1 + 500) # 출력: 1000 KRW (__add__ 호출)
print(1000 + m1) # 출력: 1500 KRW (__radd__ 호출)
print(2000 - m1) # 출력: 1500 KRW (__rsub__ 호출)
5. 주의사항: 뺄셈과 나눗셈의 비대칭성
덧셈이나 곱셈은 교환 법칙이 성립하기 때문에 __radd__를 __add__로 연결해도 무방합니다. 하지만 뺄셈(__rsub__)이나 나눗셈(__rtruediv__)은 피연산자의 위치가 바뀌면 결과가 완전히 달라집니다. 따라서 역방향 메서드 내부에서 other - self.amount와 같이 순서를 정확히 명시해야 의도치 않은 버그를 방지할 수 있습니다.
6. 결론: 전문가다운 코드의 한 끝 차이
파이썬다운(Pythonic) 코드는 단순히 돌아가는 코드가 아니라, 어떤 상황에서도 사용자(혹은 동료 개발자)가 기대하는 대로 자연스럽게 동작하는 코드입니다. __radd__를 포함한 역방향 연산자를 적절히 배치하는 것만으로도 여러분의 라이브러리나 모듈은 파이썬 기본 데이터 타입과 완벽하게 융합될 것입니다.
7. 내용의 출처 및 참조
- Python Official Documentation: Data Model - Emulating numeric types
- Fluent Python 2nd Edition (Luciano Ramalho) - Chapter 16: Operator Overloading
- Real Python: Operator Overloading in Python
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] 표준 라이브러리 활용 방법 5가지와 외부 패키지 해결 차이 (0) | 2026.03.26 |
|---|---|
| [PYTHON] 병렬 처리 시 발생하는 좀비 프로세스 방지 및 해결을 위한 3가지 핵심 방법과 언어 별 차이 (0) | 2026.03.26 |
| [PYTHON] 효율적인 리소스 관리를 위한 contextmanager 내부 동작 원리와 yield를 활용한 3가지 해결 방법 (0) | 2026.03.26 |
| [PYTHON] 다중 상속의 미학, super()가 부모를 찾는 1가지 핵심 알고리즘과 해결 방법 (0) | 2026.03.26 |
| [PYTHON] __slots__와 __dict__ 혼용 시 발생하는 3가지 내부 변화와 메모리 최적화 해결 방법 (0) | 2026.03.26 |