当参数名称与 Typing.Protocol 中定义的名称不同时,发生 mypy 错误。

问题描述 投票:0回答:2
以下代码首先定义协议

Proto

,然后定义一个采用该协议的变量的函数。然后定义类
A
B
,我认为它们都遵循协议,尽管只有
B.__call__
的参数名称与协议不同(在
Proto
中它是
x
,在
B
中它是
y
) ).

通过mypy检查以下代码后,出现以下错误

main.py:20: error: Argument 1 to "func" has incompatible type "B"; expected "Proto"
看来,协议不仅强制类型,还强制参数名称。这是有意的行为吗?或者 mypy 有什么问题吗?

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())
    
python protocols mypy python-typing
2个回答
3
投票
您可以将

Proto

 
p
 称为 
p(0)
p(x=0)
B
 不满足第二个。如果您希望 
B
 有效,您可以强制使用位置参数

class Proto(Protocol): def __call__(self, x: int, /) -> int: ...
    

1
投票

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

或者,您可以使用

__dunder_beginning

 名称来表示“我不关心该名称 - 允许任何名称”。 
mypy
 支持它(文档
这里),并且由 PEP484 支持。 Typeshed 使用此语法,因此所有类型检查器都应该支持它。这是向后兼容的(posonly 参数在 3.8 中引入,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())

通过了类型检查

这不适用于

*args

**kwargs
,因为无论如何他们的名字都不会被考虑在内。

© www.soinside.com 2019 - 2024. All rights reserved.