numbers --- Các lớp cơ sở trừu tượng bằng số

Source code: Lib/numbers.py


Mô-đun numbers (PEP 3141) xác định hệ thống phân cấp của abstract base classes số để xác định dần dần nhiều hoạt động hơn. Không có loại nào được xác định trong mô-đun này nhằm mục đích khởi tạo.

class numbers.Number

Gốc của hệ thống phân cấp số. Nếu bạn chỉ muốn kiểm tra xem một đối số x có phải là một số hay không mà không quan tâm đến loại nào, hãy sử dụng isinstance(x, Number).

Tháp số

class numbers.Complex

Các lớp con của loại này mô tả các số phức và bao gồm các phép toán hoạt động trên loại complex tích hợp sẵn. Đó là: chuyển đổi sang complexbool, real, imag, +, -, *, /, **, abs(), conjugate(), ==!=. Tất cả ngoại trừ -!= đều trừu tượng.

real

Trừu tượng. Lấy thành phần thực của số này.

imag

Trừu tượng. Lấy thành phần ảo của số này.

abstractmethod conjugate()

Trừu tượng. Trả về liên hợp phức. Ví dụ: (1+3j).conjugate() == (1-3j).

class numbers.Real

Đối với Complex, Real thêm các phép toán hoạt động trên số thực.

Nói tóm lại, đó là: chuyển đổi sang float, math.trunc(), round(), math.floor(), math.ceil(), divmod(), //, %, <, <=, >>=.

Real cũng cung cấp các giá trị mặc định cho complex(), real, imagconjugate().

class numbers.Rational

Phân loại Real và thêm các thuộc tính numeratordenominator. Nó cũng cung cấp một mặc định cho float().

Các giá trị numeratordenominator phải là phiên bản của Integral và phải ở mức thấp nhất với denominator dương.

numerator

Trừu tượng. Tử số của số hữu tỉ này.

denominator

Trừu tượng. Mẫu số của số hữu tỉ này.

class numbers.Integral

Phân loại Rational và thêm chuyển đổi thành int. Cung cấp các giá trị mặc định cho float(), numeratordenominator. Thêm các phương thức trừu tượng cho pow() với các phép toán mô đun và chuỗi bit: <<, >>, &, ^, |, ~.

Lưu ý dành cho người triển khai kiểu

Người triển khai nên cẩn thận để làm cho các số bằng nhau bằng nhau và băm chúng thành cùng một giá trị. Điều này có thể tinh tế nếu có hai phần mở rộng khác nhau của số thực. Ví dụ: fractions.Fraction triển khai hash() như sau:

chắc chắn __hash__(tự):
    nếu self.mẫu số == 1:
        số nguyên # Get đúng.
        hàm băm trả về (self.numerator)
    # Expensive kiểm tra, nhưng chắc chắn là đúng.
    nếu tự == float(tự):
        trả về hàm băm(float(self))
    khác:
        hàm băm của bộ # Use để tránh tỷ lệ va chạm cao trên
        phân số # simple.
        hàm băm trả về((self.numerator, self.mẫu số))

Thêm nhiều số ABC hơn

Tất nhiên, có nhiều ABC khả thi hơn cho các số và đây sẽ là một hệ thống phân cấp kém nếu nó loại trừ khả năng thêm các số đó. Bạn có thể thêm MyFoo giữa ComplexReal bằng:

lớp MyFoo(Phức tạp): ...
MyFoo.register(Thực)

Thực hiện các phép tính số học

Chúng tôi muốn triển khai các phép toán số học để các phép toán ở chế độ hỗn hợp gọi một triển khai mà tác giả biết về loại của cả hai đối số hoặc chuyển đổi cả hai thành loại được xây dựng gần nhất và thực hiện thao tác ở đó. Đối với các kiểu con của Integral, điều này có nghĩa là __add__()__radd__() phải được xác định là:

lớp MyIntegral(Tích phân):

    def __add__(bản thân, người khác):
        nếu isinstance(other, MyIntegral):
            trả về do_my_adding_stuff(self, other)
        Elif isinstance(other, OtherTypeIKnowAbout):
            trả về do_my_other_adding_stuff(self, other)
        khác:
            trả về Chưa thực hiện

    def __radd__(bản thân, người khác):
        nếu isinstance(other, MyIntegral):
            trả về do_my_adding_stuff(other, self)
        Elif isinstance(other, OtherTypeIKnowAbout):
            trả về do_my_other_adding_stuff(other, self)
        Elif isinstance(khác, Tích phân):
            trả về int(other) + int(self)
        Elif isinstance(other, Real):
            trả về float(other) + float(self)
        Elif isinstance(other, Complex):
            trả về phức tạp (khác) + phức tạp (tự)
        khác:
            trả về Chưa thực hiện

Có 5 trường hợp khác nhau cho thao tác kiểu hỗn hợp trên các lớp con của Complex. Tôi sẽ gọi tất cả các mã ở trên không đề cập đến MyIntegralOtherTypeIKnowAbout là "bản soạn sẵn". a sẽ là một phiên bản của A, là một kiểu con của Complex (a : A <: Complex) và b : B <: Complex. Tôi sẽ xem xét a + b:

  1. Nếu A xác định __add__() chấp nhận b thì tất cả đều ổn.

  2. Nếu A quay trở lại mã soạn sẵn và trả về giá trị từ __add__(), thì chúng ta sẽ bỏ lỡ khả năng B định nghĩa một __radd__() thông minh hơn, vì vậy mã soạn sẵn sẽ trả về NotImplemented từ __add__(). (Hoặc A có thể không triển khai __add__().)

  3. Sau đó, __radd__() của B sẽ có cơ hội. Nếu nó chấp nhận a, tất cả đều ổn.

  4. Nếu nó rơi trở lại bản soạn sẵn thì không còn phương pháp nào khả thi nữa để thử, vì vậy đây là nơi triển khai mặc định.

  5. Nếu B <: A, Python thử B.__radd__ trước A.__add__. Điều này không sao cả, vì nó được triển khai với kiến ​​thức về A nên nó có thể xử lý các trường hợp đó trước khi ủy quyền cho Complex.

Nếu A <: ComplexB <: Real không chia sẻ bất kỳ kiến thức nào khác thì thao tác chia sẻ thích hợp là thao tác liên quan đến complex tích hợp và cả __radd__() đều ở đó, vì vậy a+b == b+a.

Bởi vì hầu hết các thao tác trên bất kỳ loại nhất định nào sẽ rất giống nhau, nên có thể hữu ích khi xác định hàm trợ giúp tạo ra các phiên bản tiến và lùi của bất kỳ toán tử nhất định nào. Ví dụ: fractions.Fraction sử dụng:

def _operator_fallbacks(monomorphic_operator, fallback_operator):
    def về phía trước (a, b):
        if isinstance(b, (int, Fraction)):
            trả về monomorphic_operator(a, b)
        Elif isinstance(b, float):
            trả về fallback_operator(float(a), b)
        Elif isinstance(b, complex):
            trả về fallback_operator(complex(a), b)
        khác:
            trả về Chưa thực hiện
    chuyển tiếp.__name__ = '__' + fallback_operator.__name__ + '__'
    chuyển tiếp.__doc__ = monomorphic_operator.__doc__

    def đảo ngược (b, a):
        nếu isinstance(a, Rational):
            số nguyên # Includes.
            trả về monomorphic_operator(a, b)
        Elif isinstance(a, Real):
            trả về fallback_operator(float(a), float(b))
        Elif isinstance(a, Complex):
            trả về fallback_operator(complex(a), complex(b))
        khác:
            trả về Chưa thực hiện
    đảo ngược.__name__ = '__r' + fallback_operator.__name__ + '__'
    đảo ngược.__doc__ = monomorphic_operator.__doc__

    quay về phía trước, ngược lại

def _add(a, b):
    """a + b"""
    trả về Phân số(a.tử số * b.mẫu số +
                    b.tử số * a.mẫu số,
                    a.mẫu số * b.mẫu số)

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

# ...