代码之家  ›  专栏  ›  技术社区  ›  HiroIshida

当参数名称与键入时定义的名称不同时,出现mypy错误。协议

  •  2
  • HiroIshida  · 技术社区  · 3 年前

    以下代码首先定义了协议 Proto 然后定义一个函数,该函数采用遵循该协议的变量。然后定义类 A 和 B 我认为两者都遵循协议,尽管只有的参数名称 B.__call__ 与协议不同(在 Proto 是的 x 和在 B 它是 y ).

    在mypy检查了以下代码后,出现了以下错误

    main.py:20: error: Argument 1 to "func" has incompatible type "B"; expected "Proto"
    

    看来,Protocol不仅强制类型,还强制参数名称。这是故意的行为吗?还是八哥出了什么问题?

    from typing import Protocol
    
    class Proto(Protocol):
    
        def __call__(self, x: int) -> int:
            ...
    
    def func(f: Proto):
        pass
    
    class A:
        def __call__(self, x: int) -> int:
            return x
    
    class B:
        def __call__(self, y: int) -> int:
            return y
    
    func(A())
    func(B())
    
    1 回复  |  直到 3 年前
        1
  •  3
  •   joel DeyaEldeen    3 年前

    你可以打电话给 Proto p 作为 p(0) 或 p(x=0) . B 不能满足第二个。如果你愿意 B 为了有效,可以强制使用位置参数

    class Proto(Protocol):
        def __call__(self, x: int, /) -> int:
            ...
    
        2
  •  1
  •   STerliakov Iver Finne    3 年前

    注意:这个答案是为那些需要向后兼容性的人提供的:对于python 3.8和更高版本,使用仅位置参数声明。

    或者,您可以使用 __dunder_beginning 名字要说“我不在乎名字——允许任何”。 mypy 支持它(文档 here ),并且由支持 PEP484 . Typeshed uses this syntax ,因此所有类型检查器都应该支持它。这是向后兼容的(在3.8中引入了posonly参数,3.7仍然有效)声明协议不尊重参数名称的方式。

    # example from docs above
    from typing import Callable, TypeVar
    from typing_extensions import Protocol
    
    T = TypeVar('T')
    
    class Copy(Protocol):
        def __call__(self, __origin: T) -> T: ...
    
    copy_a: Callable[[T], T]
    copy_b: Copy
    
    copy_a = copy_b  # OK
    copy_b = copy_a  # Also OK
    
    # Your example
    from typing import Protocol
    
    class Proto(Protocol):
        def __call__(self, __x: int) -> int:  # Change here
            ...
    
    def func(f: Proto):
        pass
    
    class A:
        def __call__(self, x: int) -> int:
            return x
    
    class B:
        def __call__(self, y: int) -> int:
            return y
    
    func(A())
    func(B())
    

    这个 passes type checking .

    这不适用于 *args 和 **kwargs ,因为他们的名字无论如何都没有被考虑在内。

    推荐文章