도비LOG(跳飛錄)

도비의 AI 엔지니어 도전기

Python

[전문가를 위한 파이썬] 13장 연산자 오버로딩: 제대로 하기

나쁜도비 2024. 9. 8. 16:12

13.1. 연산자 오버로딩 기본 지식

- 파이썬은 다음과 같은 제한을 두어 융통성, 사용성, 안전성을 적절히 유지한다.

1. 내장 자료형에 대한 연산자는 오버로딩할 수 없다.

2. 새로운 연산자를 생성할 수 없으며, 기존 연산자를 오버로딩만 할 수 있다.

3. is, and, or, not 연산자는 오버로딩할 수 없다(그러나 &, |, ~ 비트 연산자는 가능하다).

 

 

13.2. 단항 연산자

- (__neg__): 단항 산술 부정. x가 -2이면 -x는 2이다.

+ (__pos__): 단항 산술 덧셈. 일반적으로 x와 +x는 동일하지만, 그렇지 않은 경우도 있다.

~ (__invert__): 정수형의 비트 반전. ~x는 -(x+1)로 정의된다(~x == -(x+1)). x가 2면, ~x는 -3이다.

 

- 단항 연산자는 self 인수 하나를 받는 적절한 특별 메서드를 구현함으로써 구현할 수 있다.

 

 

13.3. 벡터를 더하기 위해 + 오버로딩하기

- 길이가 다른 두 개의 Vector 객체를 더했을 때 짧은 쪽 벡터의 빈 공간을 0으로 채우는 __add__() 메서드 구현하기

# Vector 클래스 내부
def __add__(self, other):
  paris = itertools.zip_longest(self, other, fillvalue=0.0) # 길이가 다를 경우 짧은 쪽 반복형의 빠진 값을 fillvalue로 채운다.
  return Vector(a + b for a, b in pairs) # 새로운 Vector 객체 생성

 

- __radd__() 메서드는 __add__() 메서드의 역순 버전이다.

# Vector 클래스 내부
def __add__(self, other):
  paris = itertools.zip_longest(self, other, fillvalue=0.0) # 길이가 다를 경우 짧은 쪽 반복형의 빠진 값을 fillvalue로 채운다.
  return Vector(a + b for a, b in pairs) # 새로운 Vector 객체 생성

def __radd__(self, other): # __radd__()는 단지 __add__() 메서드에 처리를 위임한다.
  return self + other

 

- ohter 피연산자의 자료형이나 그 안에 들어 있는 요소의 자료형을 검사하지 않고, 대신 예외를 잡은 후 NotImplemented를 반환함으로써 벡터 덧셈을 수행하는 특별 메서드를 다음과 같이 구현할 수 있다.

def __add__(self, other):
  try:
    pairs = itertools.zip_longest(self, other, fillvalue=0.0)
    return Vector(a + b for a, b in pairs)
  except TypeError:
    return NotImplemented

def __radd__(self, other):
  return self + other

 

 

13.4. 벡터를 스칼라와 곱하기 위해 * 오버로딩하기

def __mul__(self, scalar):
  if isinstance(scalar, numbers.Real): # 자료형 검사. 
    return Vector(n * scalar for n in self)
  else: 
    return NotImplemented

def __rmul__(self, scalar):
  return self * scalar

 

 

13.5. 향상된 비교 연산자

- 개선된 __eq__() 메서드

def __eq__(self, other):
  if isinstance(other, Vector):
    return (len(self) == len(other) and
            all(a == b for a, b in zip(self, other)))
  else:
    return NotImplemented

 

 

13.6. 복합 할당 연산자

+와 +=를 지원하기 위해 BingoCage를 확장한 클래스

import itertools

class AddableBingoCage(BingoCage):
  def __add__(self, other):
    if isinstance(other, Tombola):
      return AddableBingoCage(self.inspect() + other.inspect()) # other 객체에서 항목을 가져온다.
    else:
      return NotImplemented

  def __iadd__(self, other):
    if isinstance(other, Tombola):
      other_iterable = other.inspect()
    else:
      try:
        other_iterable = iter(other) # Tombola 객체가 아닐 때는 other의 반복자를 가져온다.
      except TypeError:
        self_cls = type(self).__name__
        msg = "right operand in += must be {!r} or an iterable"
        raise TypeError(msg.format(self_cls))
    self.load(other_iterable) # other_iterable을 self에 로딩한다.
    return self # 할당 연산 특별 메서드는 반드시 self를 반환해야 한다.

__add__(): AddableBingoCage()를 호출해서 생성된 새로운 객체를 반환한다.

__iadd__(): 객체 자신을 변경한 후 self를 반환한다.

 

 

728x90