# `numbers` — 숫자 추상 베이스 클래스

소스 코드: Lib/numbers.py

`numbers` 모듈(PEP 3141)은 숫자에 대한 추상 베이스 클래스 의 계층 구조를 정의합니다. 계층 구조가 깊어질수록 더 많은 연산이 정의되어 있습니다. 이 모듈에 정의된 모든 형은 인스턴스로 만들 수 없습니다.

class numbers.Number

  숫자 계층의 최상위 클래스입니다. 형에 상관없이 인자 x 가 숫자인지 확인하려면 `isinstance(x, Number)` 를 사용하세요.

## 숫자 계층

class numbers.Complex

  이 서브 클래스는 복소수를 표현하고 내장 `complex` 형에 사용되는 연산을 포함합니다. 여기에는 `complex` 와 `bool` 형으로의 변환과 `real`, `imag`, `+`, `-`, `*`, `/`, `**`, `abs()`, `conjugate()`, `==`, `!=` 이 포함됩니다. `-` 와 `!=` 를 제외하고는 모두 추상입니다.

  real

    추상. 복소수의 실수부를 반환합니다.

  imag

    추상. 복소수의 허수부를 반환합니다.

  abstractmethod conjugate()

    추상 메서드. 켤레 복소수를 반환합니다. 예를 들어 `(1+3j).conjugate() == (1-3j)` 입니다.

class numbers.Real

  `Real` 클래스는 `Complex` 클래스에 실수 연산을 추가합니다.

  요약하면 `float` 로의 변환과 `math.trunc()`, `round()`, `math.floor()`, `math.ceil()`, `divmod()`, `//`, `%`, `<`, `<=`, `>`, `>=` 가 포함됩니다.

  이 클래스는 또한 `complex()`, `real`, `imag`, `conjugate()` 를 위한 기본값을 제공합니다.

class numbers.Rational

  `Real` 의 하위 형이고 `numerator` 와 `denominator` 프로퍼티가 추가됩니다. 또한 `float()` 함수를 위한 기본값을 제공합니다.

  The `numerator` and `denominator` values should be instances of `Integral` and should be in lowest terms with `denominator` positive.

  numerator

    Abstract. The numerator of this rational number.

  denominator

    Abstract. The denominator of this rational number.

class numbers.Integral

  `Rational` 의 하위 형이고 `int` 클래스로 변환 기능이 추가됩니다. `float()`, `numerator`, `denominator` 를 위한 기본값을 제공합니다. 모듈러스가 있는 `pow()`를 위한 추상 메서드와 비트 연산 `<<`, `>>`, `&`, `^`, `|`, `~` 를 추가합니다.

## 형 구현자를 위한 주의 사항

구현자는 동일한 숫자가 같게 취급되고 같은 값으로 해싱되도록 해야 합니다. 만약 종류가 다른 실수의 하위 형이 있는 경우 조금 까다로울 수 있습니다. 예를 들어 `fractions.Fraction` 클래스는 `hash()` 함수를 다음과 같이 구현합니다:

    def __hash__(self):
        if self.denominator == 1:
            # 정수입니다.
            return hash(self.numerator)
        # 비싼 검사이지만, 확실히 맞습니다.
        if self == float(self):
            return hash(float(self))
        else:
            # 간단한 분수에서의 높은 충돌률을 피하기위해 튜플의 해시를 사용합니다.
            return hash((self.numerator, self.denominator))

### 더 많은 숫자 추상 베이스 클래스(ABC) 추가

물론 숫자를 위한 ABC를 추가하는 것이 가능합니다. 그렇지 않으면 엉망으로 상속 계층이 구현될 것입니다. `Complex` 와 `Real` 사이에 다음과 같이 `MyFoo` 를 추가할 수 있습니다:

    class MyFoo(Complex): ...
    MyFoo.register(Real)

### 산술 연산 구현

다른 형에 대한 연산은 두 인자의 형에 관해 알고 있는 구현을 호출하거나 두 인자를 가장 비슷한 내장형으로 변환하여 연산하도록 산술 연산을 구현하는 것이 좋습니다. `Integral` 클래스의 하위 형일 경우에 `__add__()` 와 `__radd__()` 메서드는 다음과 같이 정의되어야 함을 의미합니다:

    class MyIntegral(Integral):

        def __add__(self, other):
            if isinstance(other, MyIntegral):
                return do_my_adding_stuff(self, other)
            elif isinstance(other, OtherTypeIKnowAbout):
                return do_my_other_adding_stuff(self, other)
            else:
                return NotImplemented

        def __radd__(self, other):
            if isinstance(other, MyIntegral):
                return do_my_adding_stuff(other, self)
            elif isinstance(other, OtherTypeIKnowAbout):
                return do_my_other_adding_stuff(other, self)
            elif isinstance(other, Integral):
                return int(other) + int(self)
            elif isinstance(other, Real):
                return float(other) + float(self)
            elif isinstance(other, Complex):
                return complex(other) + complex(self)
            else:
                return NotImplemented

`Complex` 클래스의 서브클래스에는 다섯 가지의 서로 다른 혼합형 연산이 있습니다. 위의 코드에서 `MyIntegral` 와 `OtherTypeIKnowAbout` 를 제외한 나머지를 기본구조라고 하겠습니다. `a` 는 `Complex` 의 하위 형인 `A` 의 인스턴스입니다(즉 `a : A <: Complex` 입니다). 비슷하게 `b : B <: Complex` 입니다. `a + b` 인 경우를 생각해 보겠습니다:

1. 만약 `A` 가 `b` 를 받는 `__add__()` 메서드를 정의했다면 모든 것이 문제없이 처리됩니다.

2. `A` 가 기본구조 코드로 진입하고 `__add__()`로 부터 어떤 값을 반환한다면 `B` 가 똑똑하게 정의한 `__radd__()` 메서드를 놓칠 수 있습니다. 이를 피하려면 기본구조는 `__add__()` 에서 `NotImplemented` 를 반환해야 합니다. (또는 `A` 가 `__add__()` 메서드를 전혀 구현하지 않을 수도 있습니다.)

3. 그다음 `B` 의 `__radd__()` 메서드가 기회를 얻습니다. 이 메서드가 `a` 를 받을 수 있다면 모든 것이 문제없이 처리됩니다.

4. 기본구조 코드로 돌아온다면 더 시도해 볼 수 있는 메서드가 없으므로 기본적으로 수행될 구현을 작성해야 합니다.

5. 만약 `B <: A` 라면 파이썬은 `A.__add__` 메서드 전에 `B.__radd__` 를 시도합니다. `A` 에 대해서 알고 `B` 가 구현되었기 때문에 이런 행동은 문제없습니다. 따라서 `Complex` 에 위임하기 전에 이 인스턴스를 처리할 수 있습니다.

만약 어떤 것도 공유하지 않는 `A <: Complex` 와 `B <: Real` 라면 적절한 공유 연산(shared operation)은 내장 `complex` 클래스에 연관된 것입니다. 양쪽의 `__radd__()` 메서드가 여기에 해당하므로 `a+b == b+a` 가 됩니다.

대부분 주어진 어떤 형에 대한 연산은 매우 비슷하므로, 주어진 연산자의 정방향(forward) 인스턴스와 역방향(reverse) 인스턴스를 생성하는 헬퍼 함수를 정의하는 것이 유용합니다. 예를 들어 `fractions.Fraction` 클래스는 다음과 같이 사용합니다:

    def _operator_fallbacks(monomorphic_operator, fallback_operator):
        def forward(a, b):
            if isinstance(b, (int, Fraction)):
                return monomorphic_operator(a, b)
            elif isinstance(b, float):
                return fallback_operator(float(a), b)
            elif isinstance(b, complex):
                return fallback_operator(complex(a), b)
            else:
                return NotImplemented
        forward.__name__ = '__' + fallback_operator.__name__ + '__'
        forward.__doc__ = monomorphic_operator.__doc__

        def reverse(b, a):
            if isinstance(a, Rational):
                # 정수를 포함합니다.
                return monomorphic_operator(a, b)
            elif isinstance(a, Real):
                return fallback_operator(float(a), float(b))
            elif isinstance(a, Complex):
                return fallback_operator(complex(a), complex(b))
            else:
                return NotImplemented
        reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
        reverse.__doc__ = monomorphic_operator.__doc__

        return forward, reverse

    def _add(a, b):
        """a + b"""
        return Fraction(a.numerator * b.denominator +
                        b.numerator * a.denominator,
                        a.denominator * b.denominator)

    __add__, __radd__ = _operator_fallbacks(_add, operator.add)

    # ...