考虑一个也用协议注释的Python协议属性.我发现在这种情况下,即使我的定制数据类型遵循嵌套协议,mypy和Pyright也会报告错误.例如,在下面的代码中,Outer遵循HasHasA协议,因为它有hasa: HasA,因为Inner遵循HasA协议.

from dataclasses import dataclass
from typing import Protocol

class HasA(Protocol):
    a: int

class HasHasA(Protocol):
    hasa: HasA

@dataclass
class Inner:
    a: int

@dataclass
class Outer:
    hasa: Inner

def func(b: HasHasA): ...

o = Outer(Inner(0))
func(o)

但是,mypy显示以下错误.

nested_protocol.py:22: error: Argument 1 to "func" has incompatible type "Outer"; expected "HasHasA"  [arg-type]
nested_protocol.py:22: note: Following member(s) of "Outer" have conflicts:
nested_protocol.py:22: note:     hasa: expected "HasA", got "Inner"

我的代码有什么问题?

推荐答案

有一个issue on GitHub,和你的例子几乎一模一样.我认为motivating case on the mypy docs很好地解释了为什么这是非法的.将 struct 类比应用到您的示例中,让我们填充func的实现并略微调整Inner:

def func(b: HasHasA) -> None:
    b.hasa.a += 100 - 100

@dataclass
class Inner:
    a: bool

o = Outer(Inner(bool(0)))
func(o)
if o.hasa.a is False:
    print("Oh no! This is still False!")
else:
    print("This is true now!")

这当然是一个人为的例子,但它表明,如果类型判断器没有警告您这一点,内部协议可以扩大内部类型并执行值Mutations ,并且您可以静默地执行类型不安全的操作.

正如mypy文档所建议的,解决方案是将外部协议的变量设为只读:

class HasHasA(Protocol):
    @property
    def hasa(self) -> HasA:
        ...

Python-3.x相关问答推荐

使用Python装载. iso文件

如何从Django连接到Neo4J s AuraDB(免费层)?'

如何验证具有内部json字符串的json字符串?

Python多处理池:缺少一个进程

从.csv导入将文件夹路径加入到文件名

向前/向后移动导致移动行的数据不可见

添加任意数量的 pandas 数据框

如何提高 snowpark 程序的性能?

两个 y 轴在零处对齐的 plotly barplot

Sunburst 折线图可视化

过滤列表中的所有字典以使用特定键并忽略其他键?

pytorch 中 mps 设备的 manual_seed

以不规则频率识别数据框日期时间列上缺失的日期,并用关联值填充它们

这种类型提示有什么作用?

Python pandas将单元格值移动到同一行中的另一个单元格

你如何表达一个没有参数的 Python Callable?

TypeError:JSON 对象必须是 str,而不是 'dict'

如何从字典中打印特定键值?

Pyodbc:登录超时错误

如何从Pandas 中的字符串中提取前8个字符