본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 객체 지향의 유연함을 완성하는 __radd__ 등 7가지 역방향 연산자 활용 방법과 해결 시나리오

by Papa Martino V 2026. 3. 26.
728x90

역방향 연산자 (Reflected/Right Operators)
역방향 연산자 (Reflected/Right Operators)

 

파이썬에서 클래스를 설계할 때 가장 많이 간과하는 부분 중 하나가 바로 역방향 연산자(Reflected/Right Operators)입니다. 단순히 __add__만 정의했다고 해서 우리의 객체가 모든 상황에서 완벽하게 동작하는 것은 아닙니다. 특히 외부 라이브러리의 기본 타입(int, float 등)과 내가 만든 커스텀 객체를 혼합하여 연산할 때 발생하는 'TypeError'를 우아하게 해결하는 열쇠가 바로 __radd__와 같은 메서드에 있습니다. 본 포스팅에서는 파이썬 연산자 오버로딩의 깊은 곳을 탐구하며, 'r' 메서드가 왜 존재하며, 일반 메서드와 어떤 차이가 있는지, 그리고 이를 통해 코드의 견고함을 3배 이상 높이는 구체적인 방법을 제시합니다.


1. 왜 'r'이 붙은 메서드가 필요한가? (문제 인식)

파이썬에서 a + b 연산을 수행할 때, 인터프리터는 다음의 단계를 거칩니다.

  1. 먼저 a.__add__(b)를 호출하려고 시도합니다.
  2. 만약 a__add__가 없거나, 호출 결과가 NotImplemented를 반환한다면?
  3. 비로소 파이썬은 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
728x90