[Python] 20. 연산자 오버로딩
본 포스팅은 “윤성우의 열혈 파이썬 중급편” 책 내용을 기반으로 작성되었습니다. 잘못된 내용이 있을 경우 지적해 주시면 감사드리겠습니다.
20-1. 연산자 오버로딩 간단히 이해하기
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 # == anct.__add__(100)
acnt - 50 # == acnt.__sub__(50)
print(acnt()) # == print(acnt.__call__())
main()
(결과) __add__
__sub__
__call__
James01:150
acnt + 100 이 __add__ 호출로 이어지는 것! 이것이 연산자 오버로딩 이다!
20-2. 적절한 형태로 +와 - 연산자 오버로딩
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)
예제처럼 약간 +와 -의 의미가 변형되더라도, 그 뜻이 통하도록 연산자 오버로딩이 동작되어야 한다!
20-3. 메소드 __str__의 정의
__str__은 문자열이 반환되도록 정의되어야 한다.
또한, 이 문자열은 해당 객체의 정보를 담고 있어야 한다!
class Simple:
def __init__(self, i):
self.i = i
s = Simple(10)
print(s)
s.__str__()
(결과) __main__.Simple object at 0x0000024AF2681DD8>
'__main__.Simple object at 0x0000024AF2681DD8>'
보다시피 __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)
20-4. 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
print(v1, id(v1))
main()
(결과) Vector(2, 2) 2520917744440
Vector(9, 9) 2520917745224
+= 연산 수행시, v1에는 다른 객체가 저장된다(주소값이 다름!)
이는 수정 불가능한 immutable 객체이기 때문인데, mutable 객체일 경우 동일한 객체에 저장된다.
n = [1, 2]
id(n)
n += [3]
id(n) # 연산 후에도 위치가 동일하다!
(결과) 2520910226120
2520910226120
그럼 우리가 만든 클래스의 객체는 어떻게 immutable, mutable 객체를 조정할 수 있을까? 바로 __add__와 __iadd__의 차이다!
__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 += v2
print(v1, id(v1))
main()
(결과) Vector(2, 2) 2520917745336
Vector(9, 9) 2520917745336
+=, -= 같은 연산자들을 가리켜 ‘in-place 연산자’ 라고 한다! in-place 연산자를 오버로딩 할 때, 반드시 self를 반환해야 한다.
20-5. Account 클래스 수정하기
20-1의 Account 클래스 예제를 수정해보자!
class Account:
def __init__(self, aid, abl):
self.aid = aid
self.abl = abl
def __iadd__(self, m):
self.abl += m
return self
def __isub__(self, m):
self.abl -= m
return self
def __str__(self):
return '{0}, {1}'.format(self.aid, self.abl)
def main():
acnt = Account('James01', 100)
acnt += 130
print(acnt)
acnt -= 50
print(acnt)
main()
(결과) James01, 230
James01, 180
Leave a comment