繁体   English   中英

Python中是否有“Addable”协议或抽象基class? 如果不是,人们将如何定义它?

[英]Is there an "Addable" protocol or abstract base class in Python? If not how would one define it?

typing模块包含许多协议和抽象基类,这些协议和抽象基类正式指定在数据 model中非正式描述的协议,因此它们可用于类型提示。

但是我无法为支持__add__ 是否有此类协议的任何正式规范? 如果不是这样的实现会是什么样子?

更新:

因为我对这样的 class 感兴趣是为了打字,所以这样的 class 只有在它自己完全打字时才有用,就像typing模块中的例子一样。

据我所知,没有预定义的Addable协议。 你可以自己定义一个:

from typing import Protocol, TypeVar


T = TypeVar("T")


class Addable(Protocol):
    def __add__(self: T, other: T) -> T: ...

该协议要求被加数和结果共享一个共同的祖先类型。

然后可以按如下方式使用该协议:

Tadd = TypeVar("Tadd", bound=Addable)


def my_sum(*args: Tadd, acc: Tadd) -> Tadd:
    res = acc
    for value in args:
        res += value

    return res


my_sum("a", "b", "c", acc="") # correct, returns string "abc"
my_sum(1, 2, 6, acc=0) # correct, returns int 9
my_sum(1, 2.0, 6, acc=0) # correct, returns float 9.0
my_sum(True, False, False, acc=False) # correct, returns bool 1 (mypy reveal_type returns bool, running it in python leads to result 1)

my_sum(True, False, 1, acc=1.0) # incorrect IMHO, but not detected by mypy, returns float 3.0

my_sum(1, 2, 6, acc="") # incorrect, detected by mypy
my_sum(1, 2, "6", acc=0) # incorrect, detected by mypy

您可以使用abc 模块自己定义一个。 那里提供的 ABC 元类允许您定义一个__subclasshook__ ,您可以在其中检查 class 方法,例如__add__ 如果这个方法是为某个 class 定义的,那么它就被认为是那个 abc 的子类。

from abc import ABC

class Addable(ABC):
    @classmethod
    def __subclasshook__(cls, C):
        if cls is Addable:
            if any("__add__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

class Adder():
    def __init__(self, x):
        self.x = x
    def __add__(self, x):
        return x + self.x

inst = Adder(5)

# >>> isinstance(inst, Addable)
# True
# >>> issubclass(Adder, Addable)
# True

存在这样的协议。 只是不在通常执行的代码中......存在一个特殊的 package 称为typeshed ,类型检查器使用它向未使用任何类型提示实现的代码添加类型提示...... typeshed package 没有虽然在运行时存在。

所以你可以在类型检查期间使用_typeshed.SupportsAdd - 但要在执行期间检查你需要动态检查__add__方法或者你自己实现SupportsAdd协议......

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from _typeshed import SupportsAdd


# SupportsAdd must always be written in quotation marks when used later...
def require_adding_str_results_in_int(a_obj: "SupportsAdd[str, int]"):
    # the type checker guarantees that this should work now
    assert type(a_obj + "a str") == int

    # to check during runtime though you'd probably use
    assert hasattr(a_obj, "__add__")

希望有所帮助...很可能这是实现您自己的协议和使用@runtime_checkable装饰器的最佳方式。 您可以查看 typeshed 的源代码以获取灵感。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM