gpt4 book ai didi

python - 使用常规方法和类方法实现 Python 协议(protocol)

转载 作者:行者123 更新时间:2023-12-01 07:50:16 25 4
gpt4 key购买 nike

假设我有两个类(class) Foo1Foo2实现方法bar() :

  • Foo1 , bar()是常规方法
  • Foo2 , bar()@classmethod

  • class Foo1:

    def bar(self) -> None:
    print("foo1.bar")


    class Foo2:

    @classmethod
    def bar(cls) -> None:
    print("Foo2.bar")

    现在假设我有一个函数,它接受“任何具有 bar() 方法的东西”列表并调用它:

    def foreach_foo_call_bar(foos):
    for foo in foos:
    foo.bar()

    在运行时调用此函数可以正常工作:

    foreach_foo_call_bar([Foo1(), Foo2])

    作为 Foo1()Foo2有一个 bar()方法。

    但是,如何正确地向 foreach_foo_call_bar() 添加类型提示? ?

    我尝试创建一个 PEP544 Protocol调用 SupportsBar :

    class SupportsBar(Protocol):

    def bar(self) -> None:
    pass

    并像这样注释:

    def foreach_foo_call_bar(foos: Iterable[SupportsBar]):
    ...

    但 mypy 说:
    List item 1 has incompatible type "Type[Foo2]"; expected "SupportsBar"

    知道如何正确注释吗?

    最佳答案

    问题似乎是 Protocol专门检查是否支持实例方法,而不仅仅是存在正确名称的属性。在 Foo2 的情况下,这意味着元类需要一个名为 bar 的实例方法;以下似乎表现如预期和类型检查。

    # Define a metaclass that provides an instance method bar for its instances.
    # A metaclass instance method is almost equivalent to a class method.
    class Barrable(type):
    def bar(cls) -> None:
    print(cls.__name__ + ".bar")


    class Foo1:
    def bar(self) -> None:
    print("foo1.bar")


    class Foo2(metaclass=Barrable):
    pass


    class SupportsBar(Protocol):
    def bar(self) -> None:
    pass


    def foreach_foo_call_bar(foos: Iterable[SupportsBar]):
    for foo in foos:
    foo.bar()

    我不会声称将类方法转换为元类实例方法是一个很好的解决方法(事实上,它对静态方法没有任何作用),但它指出这是 Protocol 的基本限制。它不处理任意属性。

    关于python - 使用常规方法和类方法实现 Python 协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62242509/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com