Phép trừ nhị phân Python

[Bài đăng này đã được cập nhật nhiều lần kể từ lần đăng đầu tiên; . ]

Phản ứng đối với bài đăng trên blog của tôi về việc làm sáng tỏ quyền truy cập thuộc tính đủ tích cực đến mức tôi được truyền cảm hứng để thực hiện một bài đăng khác về mức độ cú pháp của Python thực sự chỉ là đường cú pháp. Trong bài đăng này, tôi muốn giải quyết các phép toán số học nhị phân

Cụ thể, tôi muốn làm sáng tỏ cách hoạt động của phép trừ. a - b. Bây giờ tôi đang cố tình chọn phép trừ vì nó không giao hoán. Điều này giúp đảm bảo rằng thứ tự của các thao tác có ý nghĩa quan trọng so với việc thực hiện phép cộng mà bạn có thể mắc lỗi và lật ngược ab trong quá trình thực hiện mà vẫn có kết quả như nhau

Tìm mã C

Như trong bài viết trước của tôi, chúng ta sẽ bắt đầu bằng cách xem mã byte nào mà trình thông dịch CPython biên dịch cho cú pháp

>>> def sub[]: a - b
.. 
>>> import dis
>>> dis.dis[sub]
  1           0 LOAD_GLOBAL              0 [a]
              2 LOAD_GLOBAL              1 [b]
              4 BINARY_SUBTRACT
              6 POP_TOP
              8 LOAD_CONST               0 [None]
             10 RETURN_VALUE
Tách một biểu thức trừ

Vì vậy, có vẻ như đó là những gì chúng tôi muốn đi sâu vào. Tra cứu trong

case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
0 cho bạn thấy mã C để triển khai opcode đó như sau

case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
https. //github. com/python/cpython/blob/6f8c8320e9eac9bc7a7f653b43506e75916ce8e8/Python/ceval. C#L1569-L1579

Đoạn mã quan trọng cần xem ở đây là

case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
1 triển khai ngữ nghĩa thực tế cho phép trừ. Giờ đây, việc gỡ rối chức năng đó thông qua một số macro sẽ đưa bạn đến. Những gì điều này cung cấp là một cách chung để quản lý các hoạt động nhị phân. Tuy nhiên, thay vì sử dụng nó làm tài liệu tham khảo để triển khai, chúng tôi sẽ làm việc từ mô hình dữ liệu của Python vì tôi nghĩ rằng tài liệu này rất hay và rõ ràng về ngữ nghĩa nên có đối với phép trừ

Học từ mô hình dữ liệu

Đọc qua mô hình dữ liệu, bạn sẽ phát hiện ra rằng hai phương thức đóng vai trò trong phép trừ thực hiện.

case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
3 và
case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
4

Phương pháp
case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
5

Khi xem xét a - b, phương thức

case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
5 được tìm kiếm từ loại a và sau đó b được truyền dưới dạng đối số [giống như với
def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
0 trong bài đăng trên blog của tôi về quyền truy cập thuộc tính, các phương thức đặc biệt/ma thuật được giải quyết theo loại đối tượng, không phải . Vì vậy, nếu nó được xác định,
def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
2 sẽ được sử dụng để thực hiện phép trừ

Điều đó có nghĩa là phép trừ, ở dạng đơn giản nhất, chỉ là một lệnh gọi phương thức. Hôm nay bạn có thể khái quát hóa điều này bằng cách sử dụng. Chúng tôi sẽ lập mô hình triển khai của riêng mình sau chức năng đó. Tôi sẽ sử dụng các tên

def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
4 và
def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
5 để đại diện cho bên trái và bên phải của a - b để làm cho mã ví dụ dễ theo dõi hơn

def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
Phép trừ được thực hiện thông qua cuộc gọi
case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
5

Để phía bên tay phải tham gia thông qua
def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
8

Nhưng nếu a không triển khai

case TARGET[BINARY_SUBTRACT]: {
    PyObject *right = POP[];
    PyObject *left = TOP[];
    PyObject *diff = PyNumber_Subtract[left, right];
    Py_DECREF[right];
    Py_DECREF[left];
    SET_TOP[diff];
    if [diff == NULL]
    goto error;
    DISPATCH[];
}
5 thì sao? . Điều này đảm bảo rằng cả hai bên của hoạt động đều có cơ hội thử và làm cho biểu thức hoạt động khi chúng khác nhau; . Tuy nhiên, ngay cả khi cách triển khai giống nhau, bạn vẫn muốn gọi _______8___8 trong trường hợp có vấn đề khi một trong các đối tượng là một lớp [phụ] khác

Để một loại vượt qua

Bây giờ cả hai bên của biểu thức đều tham gia. Nhưng điều gì sẽ xảy ra nếu loại đối tượng không hỗ trợ phép trừ vì một lý do nào đó [e. g.

_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
8 không hoạt động]? . Đó là một tín hiệu cho Python rằng nó nên tiếp tục và thử tùy chọn tiếp theo để thực hiện thao tác. Đối với mã của chúng tôi, điều đó có nghĩa là chúng tôi cần kiểm tra những phương thức trả về trước khi chúng tôi có thể cho rằng nó hoạt động

_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
Thực hiện phép trừ trong đó cả vế trái và vế phải của biểu thức đều có thể tham gia

Để các lớp con làm chủ xung quanh cha mẹ của chúng

Nếu bạn xem qua, bạn sẽ nhận thấy có một ghi chú. Điều nó nói là nếu vế phải của một biểu thức trừ là một lớp con của vế trái [và là một lớp con thực; cùng một lớp thì không được tính] và phương thức

def sub[lhs: Any, rhs: Any, /] -> Any:
    """Implement the binary operation `a - b`."""
    lhs_type = type[lhs]
    try:
        subtract = _mro_getattr[lhs_type, "__sub__"]
    except AttributeError:
        msg = f"unsupported operand type[s] for -: {lhs_type!r} and {type[rhs]!r}"
        raise TypeError[msg]
    else:
        return subtract[lhs, rhs]
8 khác nhau giữa hai đối tượng, thì . Nói cách khác, bạn đảo ngược thứ tự bạn thử các phương pháp nếu b là một lớp con của a

Điều này có vẻ giống như một trường hợp đặc biệt khá kỳ lạ, nhưng có logic đằng sau nó. Khi bạn phân lớp thứ gì đó, điều đó có nghĩa là bạn đang đưa logic mới vào cách thức hoạt động của một lớp so với lớp cha của nó. Logic này không nhất thiết phải tiếp xúc với lớp cha, điều đó có nghĩa là nếu một lớp cha hoạt động trên một lớp con thì nó có thể dễ dàng bỏ qua cách lớp con muốn được đối xử

Nói một cách cụ thể, hãy tưởng tượng một lớp có tên là

_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
8, khi bạn thực hiện
_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
9, bạn sẽ nhận được một thể hiện của
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
0. Bây giờ, hãy tưởng tượng bạn đã tạo một lớp con của
_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
8 được gọi là
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
2, sao cho khi bạn trừ
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
2 từ
_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
8, bạn nhận được
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
5. Nếu không có quy tắc trên, thì
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
6 sẽ dẫn đến
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
0 vì
_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
8 không biết rằng việc xóa
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
2 sẽ dẫn đến
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
5. Nhưng  với quy tắc ở trên, kết quả dự kiến ​​của
_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
5 sẽ xảy ra do a - b2 lần đầu tiên bắt đầu tạo giá trị của biểu thức [nếu là a - b3 thì kết quả đúng vẫn sẽ xảy ra vì a - b4 sẽ được gọi trước, do đó quy tắc nói

Về lý do tại sao việc triển khai

_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
5 phải khác ngay cả khi lớp con "thích hợp" được đáp ứng, điều đó bắt nguồn từ cách lớp chồng toán tử ban đầu được triển khai ở cấp độ C trong CPython. Guido và tôi đã nói đi nói lại về nó, nhưng điểm mấu chốt là ở trình độ C chỉ có phương pháp "trừ", không phải
_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
9 và
_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
5. Và vì vậy, đối với mã gọi các mô-đun mở rộng, cách mà những thứ bên trái/bên phải này xảy ra là gọi phương thức "phép trừ" với thứ tự đối số khác [i. e. a - b9 cho a0, a1 cho a2]. Nếu không có quy tắc đó, bạn sẽ gọi chính xác cùng một phương thức hai lần, điều này là dư thừa và có thể dẫn đến các lỗi tinh vi. Với quy tắc cụ thể này, bạn tránh được những vấn đề đó

_MISSING = object[]

def sub[lhs: Any, rhs: Any, /] -> Any:
        # lhs.__sub__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, "__sub__"]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__rsub__ [for knowing if rhs.__rub__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, "__rsub__"]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__rsub__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, "__rsub__"]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            raise TypeError[
                f"unsupported operand type[s] for -: {lhs_type!r} and {rhs_type!r}"
            ]
Triển khai hoàn chỉnh phép trừ trong Python

Và đó là nó. Điều này cho chúng ta một cách thực hiện đầy đủ phép trừ

Tổng quát hóa cho các hoạt động nhị phân khác

Với phép trừ ngoài lề, còn các phép toán nhị phân khác thì sao? . Vì vậy, nếu chúng ta có thể khái quát hóa cách tiếp cận này, thì chúng ta sẽ triển khai ngữ nghĩa cho 13 thao tác. a3, a4, a5, a6, a7, a8, a9, b0, b1, b2, b3, b4 và b5

Và nhờ các bao đóng và tính linh hoạt của Python trong cách các đối tượng biết chi tiết về bản thân chúng, chúng ta có thể khái quát hóa việc tạo các hàm b6

_MISSING = object[]


def _create_binary_op[name: str, operator: str] -> Any:
    """Create a binary operation function.

    The `name` parameter specifies the name of the special method used for the
    binary operation [e.g. `sub` for `__sub__`]. The `operator` name is the
    token representing the binary operation [e.g. `-` for subtraction].

    """

    lhs_method_name = f"__{name}__"

    def binary_op[lhs: Any, rhs: Any, /] -> Any:
        """A closure implementing a binary operation in Python."""
        rhs_method_name = f"__r{name}__"

        # lhs.__*__
        lhs_type = type[lhs]
        try:
            lhs_method = debuiltins._mro_getattr[lhs_type, lhs_method_name]
        except AttributeError:
            lhs_method = _MISSING

        # lhs.__r*__ [for knowing if rhs.__r*__ should be called first]
        try:
            lhs_rmethod = debuiltins._mro_getattr[lhs_type, rhs_method_name]
        except AttributeError:
            lhs_rmethod = _MISSING

        # rhs.__r*__
        rhs_type = type[rhs]
        try:
            rhs_method = debuiltins._mro_getattr[rhs_type, rhs_method_name]
        except AttributeError:
            rhs_method = _MISSING

        call_lhs = lhs, lhs_method, rhs
        call_rhs = rhs, rhs_method, lhs

        if [
            rhs_type is not _MISSING  # Do we care?
            and rhs_type is not lhs_type  # Could RHS be a subclass?
            and issubclass[rhs_type, lhs_type]  # RHS is a subclass!
            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?
        ]:
            calls = call_rhs, call_lhs
        elif lhs_type is not rhs_type:
            calls = call_lhs, call_rhs
        else:
            calls = [call_lhs,]

        for first_obj, meth, second_obj in calls:
            if meth is _MISSING:
                continue
            value = meth[first_obj, second_obj]
            if value is not NotImplemented:
                return value
        else:
            exc = TypeError[
                f"unsupported operand type[s] for {operator}: {lhs_type!r} and {rhs_type!r}"
            ]
            exc._binary_op = operator
            raise exc
Một hàm để tạo bao đóng thực hiện logic cho phép toán nhị phân

Với mã này, bạn có thể xác định phép toán trừ là b7 và sau đó lặp lại nếu cần cho các phép toán khác

Thêm thông tin

Bạn có thể tìm thêm các bài viết của tôi về việc làm sáng tỏ cú pháp của Python bằng cách xem thẻ "đường cú pháp" của blog này. Mã nguồn có thể được tìm thấy tại https. //github. com/brettcannon/desugar

Chủ Đề