파이썬 강좌 8-4편. 연산자 오버로딩(Operator Overloading)
1. 연산자 오버로딩(Operator Overloading)
이번에는 연산자 오버로딩(Operator Overloading)에 대해서 알아보려고 합니다. 이 연산자 오버로딩이란, 인스턴스 객체끼리 서로 연산을 할 수 있게끔 기존에 있는 연산자의 기능을 바꾸어 중복으로 정의하는 것을 말합니다. 예를 들어보자면, 아래와 같은 경우를 생각해 볼 수 있겠죠?
>>> class NumBox: def __init__(self, num): self.Num = num >>> n = NumBox(40) >>> n + 100 Traceback (most recent call last): File "<pyshell#5>", line 1, in <module> n + 100 TypeError: unsupported operand type(s) for +: 'NumBox' and 'int'
위 예제를 보시면, 인스턴스 객체 n에 '+' 연산자를 사용하여 100을 더하려는 코드가 보이는데 이는 지원되지 않는 연산 타입이므로 NumBox와 int간의 연산을 수행하기 힘들다는 것입니다. 그렇다면 + 연산자를 사용하여 성공적으로 클래스 NumBox 내에 있는 변수 Num의 값을 증가시키려면 어떻게 해야 할까요? 바로 우리가 배우게 될 연산자 오버로딩이란 기법을 이용하면 됩니다. 파이썬에서는 인스턴스 객체의 연산을 위해 여러가지 연산자를 미리 정의해두었는데, 이를 표로 정리하여 아래에 작성해두었습니다.
메서드(Method) |
연산자(Operator) |
사용 예 |
__add__(self, other) |
+ (이항) |
A + B, A += B |
__pos__(self) |
+ (단항) |
+A |
__sub__(self, other) |
- (이항) |
A - B, A -= B |
__neg__(self) |
- (단항) |
-A |
__mul__(self, other) |
* |
A * B, A *= B |
__truediv__(self, other) |
/ |
A / B, A /= B |
__floordiv__(self, other) |
// |
A // B, A //= B |
__mod__(self, other) |
% |
A % B, A %= B |
__pow__(self, other) |
pow(), ** |
pow(A, B), A ** B |
__lshift__(self, other) |
<< |
A << B, A <<= B |
__rshift__(self, other) |
>> |
A >> B, A >>= B |
__and__(self, other) |
& |
A & B, A &= B |
__xor__(self, other) |
^ |
A ^ B, A ^= B |
__or__(self, other) |
| |
A | B, A |= B |
__invert__(self) |
~ |
~A |
__abs__(self) |
abs() |
abs(A) |
<미리 정의된 수치 연산자>
파이썬에서 미리 정의된 함수를 중복 정의하여 우리가 정의한 동작을 수행하게 하도록 합시다. 아래 예제에서는 +와 - 연산자를 오버로딩하여 인스턴스 객체에 연산자를 사용합니다. 천천히 살펴봅시다.
>>> class NumBox: def __init__(self, num): self.Num = num def __add__(self, num): self.Num += num def __sub__(self, num): self.Num -= num >>> n = NumBox(40) >>> n + 100 >>> n.Num 140 >>> n - 110 >>> n.Num 30
위 예제를 보시면 클래스 NumBox 내에 미리 정의된 함수인 __add__, __sub__를 중복 정의하였습니다. 만약, 우리의 예상대로라면 NumBox의 인스턴스 객체에 + 연산자가 쓰였을때는 클래스 내에 있는 Num의 값이 지정한 수만큼 증가하여야 하며, - 연산자가 쓰였을때는 Num의 값이 지정된 수만큼 감소하여야 합니다. 10행을 보시면 인스턴스 객체 n에 100을 더하는 연산을 하고 있으며, 그 후 n.Num의 값을 보자 40에서 100이 증가된 140이란 결과값을 확인하실 수 있습니다. 마찬가지로 13행에서도, 인스턴스 객체 n에 110을 빼는 연산을 하고 있으며 그 후 n.Num의 값이 140에서 110이 감소되어 30이란 값을 확인하실 수 있습니다.
한가지 더 알아보자면, 위 예제에서 'n + 100'과 같은 연산은 사실상 우리가 중복 정의한 함수가 호출되는 것입니다. 이런 연산은 아래와 같이 호출된다고 생각하시면 됩니다.
n.__add__(100)
만약에, 피연산자의 순서를 앞뒤로 바꾸어도 우리가 원하는 결과값을 얻어낼 수 있을까요? 한번 아래의 예제를 통해 알아보도록 하겠습니다.
>>> 110 + n Traceback (most recent call last): File "<pyshell#20>", line 1, in <module> 110 + n TypeError: unsupported operand type(s) for +: 'int' and 'NumBox'
이게 왠일입니까? 피연산자의 순서를 바꾸었더니 우리가 원하는 결과값은 온데간데 없고, 지원되지 않는 연산 타입이란 타입 에러만 떡하니 자리를 차지하고 있습니다. 왜 이런가하니, 위와 같이 인스턴스 객체가 오른쪽으로 이동하면 __add__ 함수가 호출되는게 아니라 __radd__ 함수가 호출되기 때문입니다. 그렇기 때문에, __radd__도 역시 정의해 주어야 위와 같은 연산에서 에러가 발생하지 않습니다.
이렇게 피연산자의 순서가 뒤바뀐 경우에는 아래와 같이 연산자 이름앞에 'r'을 붙여주면 됩니다. 예를들면, 아래와 같이 말이죠.
__add__ = __radd__ __sub__ = __rsub__ __mul__ = __rmul__
이제 왜 에러가 발생하는지 알았으니, 위와 같이 앞에 'r'이 붙은 연산자를 정의하여 예제를 한번 고쳐보도록 하겠습니다.
>>> class NumBox: def __init__(self, num): self.Num = num def __add__(self, num): self.Num += num def __radd__(self, num): self.Num += num >>> n = NumBox(100) >>> 120 + n >>> n.Num 220 >>> 300 + n >>> n.Num 520
위 예제를 보시면 클래스 NumBox 내에 __radd__가 중복 정의된 것을 보실 수 있습니다. 10행에서 피연산자의 순서를 바꾸어 + 연산을 진행하고 있는데, 아무런 에러 없이 우리가 생각하던 결과를 표시하고 있습니다. 독자분들도 위의 표에 있는 함수를 중복 정의하여 여러가지 예제를 만들어가면서 연산자 오버로딩에 대한 경험을 쌓고 이해를 해보시는걸 권장합니다.
'프로그래밍 관련 > Python' 카테고리의 다른 글
파이썬 강좌 10-1편. 입출력(I/O) (10) | 2013.12.13 |
---|---|
파이썬 강좌 9편. 모듈(Module) (21) | 2013.11.10 |
파이썬 강좌 8-3편. 상속(Inheritance) (19) | 2013.10.27 |
파이썬 강좌 8-2편. 생성자와 소멸자(Constructor and Destructor) (19) | 2013.10.27 |
파이썬 강좌 8-1편. 클래스(Class) (16) | 2013.10.20 |