【发布时间】:2019-12-03 21:49:16
【问题描述】:
我正在使用 mypy 和协议,如果可能的话,我遇到了一个我想要类型提示的地方,但我无法弄清楚我应该如何设置它,这样 mypy 就不会出错。
考虑以下示例:
class TProtocol(Protocol):
t: str
@attrs(auto_attribs=True)
class T:
t: str
t2: str
@attrs(auto_attribs=True)
class T2:
t: str
def func(var: TProtocol) -> None:
if some_condition:
var: T
reveal_type(var)
else:
reveal_type(var)
虽然非常做作,但它说明了我的目标,即我有一些运行时条件,如果满足,我会根据代码库的知识知道该变量的类型。然后我想将这些知识传递给 mypy,以便进一步的类型检查使用该类型。
同样的例子可以用 Union 代替。一些运行时检查会根据代码库的知识明确告诉我我拥有哪种类型。然后,我想根据外部知识明确告诉 mypy 哪种类型用于进一步类型检查。
上面的示例引发了一个错误,指出 var 已定义。我尝试了allow_redefinition 选项,但它并没有改变输出。
【问题讨论】:
-
这与
Protocol有多大关系?您似乎想为给定的运行时分支指定一个类型。请注意,hasattr(var, "t2")是一个运行时表达式,没有什么可以阻止T2类型的值具有字段t2。 -
你是对的,没有什么能明确阻止你将字段 t2 添加到 T2。在实际代码中,它使用枚举而不是
hasattr,并且协议实际上是对象上的一个字段。基于作为对象的另一个属性的枚举,我明确地知道协议的具体类是什么。我试图使用这些知识并显式键入它,以便可以轻松地对 if 块内的代码进行类型检查。我希望通过更集中的问题示例来删除代码的详细语义。 -
协议没有一个具体类。这才是重点。任何满足协议的类都是有效的,即使是那些你没有定义的。也许您应该更新您的问题以实际匹配您要解决的问题。
-
你是对的,协议没有一个实现,但基于某些条件,我明确知道它可能在该代码库中的一个具体类。我基本上对类型有
isinstance风格的知识。我更新了问题以删除hasattr以尝试更明确地从其他方式显示我知道var必须是协议的实现,并且我想将其明确键入为该类型。现在更有意义了吗? -
这里有些混乱:1) 协议意味着支持满足它的所有类型。如果您打算仅使用 some 具体类型并不重要,您明确地将其注释为表示 all 匹配类型。 2)
somecondition和hasattr是在实例上执行的 runtime 检查。他们没有透露任何关于类型的信息。 3)如果你想让它成为一些具体的类型,你为什么不这样注释呢?Union[T, T2]似乎更合适。
标签: python-3.x mypy