简体   繁体   English

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

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

The typing module contains many protocols and abstract base classes that formally specify protocols which are informally described in the data model , so they can be used for type hints. typing模块包含许多协议和抽象基类,这些协议和抽象基类正式指定在数据 model中非正式描述的协议,因此它们可用于类型提示。

However I was unable to find such a protocol or abstract base class for objects that support __add__ .但是我无法为支持__add__ Is there any formal specification of such a protocol?是否有此类协议的任何正式规范? If not how would such an implementation look like?如果不是这样的实现会是什么样子?

Update:更新:

Since I'm interested in such a class for the purpose of typing, such a class would only be useful if it's fully type itself, like the examples in the typing module.因为我对这样的 class 感兴趣是为了打字,所以这样的 class 只有在它自己完全打字时才有用,就像typing模块中的例子一样。

To my knowledge there is no pre-defined Addable protocol.据我所知,没有预定义的Addable协议。 You can definie one yourself:你可以自己定义一个:

from typing import Protocol, TypeVar


T = TypeVar("T")


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

This protocol requires that both summands and the result share a common ancestor type.该协议要求被加数和结果共享一个共同的祖先类型。

The protocol can then be used as follows:然后可以按如下方式使用该协议:

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

You could define one yourself using the abc module .您可以使用abc 模块自己定义一个。 The ABC metaclass that is provided there allows you to define a __subclasshook__ , in which you can check for class methods such as __add__ .那里提供的 ABC 元类允许您定义一个__subclasshook__ ,您可以在其中检查 class 方法,例如__add__ If this method is defined for a certain class, it is then considered a subclass of that abc.如果这个方法是为某个 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

There exists such a protocol.存在这样的协议。 Just not in the code that's usually executed... There exists a special package called typeshed that's used by type-checkers to add type-hints to code that isn't implemented with any type-hints... The typeshed package doesn't exist during runtime though.只是不在通常执行的代码中......存在一个特殊的 package 称为typeshed ,类型检查器使用它向未使用任何类型提示实现的代码添加类型提示...... typeshed package 没有虽然在运行时存在。

So you can use _typeshed.SupportsAdd during type-checking - but to check during execution you'd need to check for the __add__ method dynamically or you implement the SupportsAdd protocol yourself...所以你可以在类型检查期间使用_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__")

Hope that helped... Most likely it's the best way to implement your own protocol and use the @runtime_checkable decorator.希望有所帮助...很可能这是实现您自己的协议和使用@runtime_checkable装饰器的最佳方式。 You can look at the source code of typeshed to get inspirations.您可以查看 typeshed 的源代码以获取灵感。

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

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