[Python] 연산자 오버로딩
연산자 오버로딩
class Account: # 계좌 클래스
def __init__(self, aid, abl):
self.aid = aid # 계좌 번호
self.abl = abl # 계좌 잔액
def __add__(self, m): # 입금
self.abl += m
print('__add__')
def __sub__(self, m): # 인출
self.abl -= m
print('__sub__')
def __call__(self): # 계좌 상황을 문자열로 반환
print('__call__')
return str(self.aid) + ':' + str(self.abl)
def main():
acnt = Account('James01', 100) # 계좌 개설
acnt + 100 # 100원 입금
# acnt.__add__(100)
acnt - 50 # 50원 인출
# acnt.__sub__(50)
print(acnt())
# print(acnt.__call__())
main()
__add__
__sub__
__call__
james01 : 150
위 코드에서 +와 같은 연산을 진행했을 때 이를 대신해서 미리 약속해 놓은 메소드가 호출되도록 하는 것이 연산자 오버로딩이다. 이러한 연산자와 호출되는 메소드의 관계는 약속되어있고 그 약속을 기반으로 위의 예제가 작성되었다.
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, o): # 벡터의 덧셈 연산
return Vector(self.x + o.x, self.y + o.y)
def __call__(self): # 벡터 정보를 문자열로 반환
return 'Vector({0}, {1})'.format(self.x, self.y)
def main():
v1 = Vector(3, 3)
v2 = Vector(7, 7)
v3 = v1 + v2
print(v1())
print(v2())
print(v3())
main()
Vector(3,3)
Vector(7,7)
Vector(10,10)
+연산자를 적절히 오버로딩한 예이다.
메소드 str 정의
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, o): # 벡터의 덧셈 연산
return Vector(self.x + o.x, self.y + o.y)
def __str__(self): # 벡터 정보를 문자열로 반환
return 'Vector({0}, {1})'.format(self.x, self.y)
def main():
v1 = Vector(3, 3)
v2 = Vector(7, 7)
v3 = v1 + v2
print(v1)
print(v2)
print(v3)
main()
Vector(3,3)
Vector(7,7)
Vector(10,10)
앞에서는 객체가 갖고 있는 정보를 출력하기 위해 call 메소드를 정의했다. 이때 객체가 갖는 정보를 단순히 눈으로 확인하는 정도의 목적이라면 str 메소드를 사용하면 된다. str 메소드는 문자열을 반환하도록 정의해야 한다.
in-place 형태의 연산자 오버로딩
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, o): # 벡터의 덧셈 연산
return Vector(self.x + o.x, self.y + o.y)
def __str__(self): # 벡터 정보를 문자열로 반환
return 'Vector({0}, {1})'.format(self.x, self.y)
def main():
v1 = Vector(2, 2)
v2 = Vector(7, 7)
print(v1, id(v1))
v1 += v2 # v1 = v1.__add__(v2)
print(v1, id(v1))
main()
Vector(2,2) 51761616
Vector(9,9) 54451088
정수와 문자열 같이 수정불가능한 immutable 객체라면 += 연산을 하면 v1에 다른 객체가 저장된다.
하지만 리스트와 같이 muutable 객체라면 +=연산을하면 저장된 위치가 달라지지 않는다.
add : + 연산에 대한 오버로딩 iadd : += 연산에 대한 오버로딩
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, o): # 벡터의 + 연산
return Vector(self.x + o.x, self.y + o.y)
def __iadd__(self, o): # 벡터의 += 연산
self.x += o.x
self.y += o.y
return self
def __str__(self): # 벡터 정보를 문자열로 반환
return 'Vector({0}, {1})'.format(self.x, self.y)
def main():
v1 = Vector(2, 2)
v2 = Vector(7, 7)
print(v1, id(v1)) # v1과 v1에 저장된 객체의 주소 정보 출력
v1 += v2 # v1 = v1.__iadd__(v2)
print(v1, id(v1)) # v1과 v1에 저장된 객체의 주소 정보 출력
main()
Vector(2,2) 52023728
Vector(9,9) 52023728
iadd 메소드를 정의하지 않고 add 메소드만 정의하면 +연산과 +=연산 모두에 있어서 이 메소드가 호출된다. 그러나 iadd 메소드를 추가로 정의하면 +연산시에는 add 메소드가 호출되고, +=연산시에는 iadd 메소드가 호출된다.