如何在 Python 中将typing.Union 转换为其子类型之一? [英] How to cast a typing.Union to one of its subtypes in Python?
问题描述
我使用的是 Python 3.6.1、mypy 和输入模块.我创建了两个自定义类型,Foo
和 Bar
,然后在我从函数返回的 dict 中使用它们.dict 被描述为将 str
映射到 Foo
和 Bar
的 Union
.然后我想在一个函数中使用这个字典中的值,每个函数只命名一个参数:
I’m using Python 3.6.1, mypy, and the typing module. I created two custom types, Foo
and Bar
, and then used them in a dict I return from a function. The dict is described as mapping str
to a Union
of Foo
and Bar
. Then I want to use values from this dict in a function that names only one argument each:
from typing import Dict, Union, NewType
Foo = NewType("Foo", str)
Bar = NewType("Bar", int)
def get_data() -> Dict[str, Union[Foo, Bar]]:
return {"foo": Foo("one"), "bar": Bar(2)}
def process(foo_value: Foo, bar_value: Bar) -> None:
pass
d = get_data()
我尝试按原样使用这些值:
I tried using the values as-is:
process(d["foo"], d["bar"])
# typing-union.py:15: error: Argument 1 to "process" has incompatible type "Union[Foo, Bar]"; expected "Foo"
# typing-union.py:15: error: Argument 2 to "process" has incompatible type "Union[Foo, Bar]"; expected "Bar"
或者使用类型:
process(Foo(d["foo"]), Bar(d["bar"]))
# typing-union.py:20: error: Argument 1 to "Foo" has incompatible type "Union[Foo, Bar]"; expected "str"
# typing-union.py:20: error: Argument 1 to "Bar" has incompatible type "Union[Foo, Bar]"; expected "int"
如何将 Union
转换为其子类型之一?
How do I cast the Union
to one of its subtypes?
推荐答案
你必须使用 cast()
:
You'd have to use cast()
:
process(cast(Foo, d["foo"]), cast(Bar, d["bar"]))
来自 PEP 484 的演员部分:
From the Casts section of PEP 484:
有时类型检查器可能需要不同类型的提示:程序员可能知道一个表达式的类型比类型检查器所能推断的更受约束.
Occasionally the type checker may need a different kind of hint: the programmer may know that an expression is of a more constrained type than a type checker may be able to infer.
没有办法拼出什么特定类型的值与字典键的什么特定值相匹配.您可能需要考虑返回一个命名元组 代替,可以按键输入:
There is no way to spell what specific types of value go with what specific value of a dictionary key. You may want to consider returning a named tuple instead, which can be typed per key:
from typing import Dict, Union, NewType, NamedTuple
Foo = NewType("Foo", str)
Bar = NewType("Bar", int)
class FooBarData(NamedTuple):
foo: Foo
bar: Bar
def get_data() -> FooBarData:
return FooBarData(foo=Foo("one"), bar=Bar(2))
现在类型提示器确切地知道每个属性类型是什么:
Now the type hinter knows exactly what each attribute type is:
d = get_data()
process(d.foo, d.bar)
或者您可以使用数据类:
from dataclasses import dataclass
@dataclass
class FooBarData:
foo: Foo
bar: Bar
这样可以更轻松地添加可选属性以及控制其他行为(例如相等性测试或排序).
which makes it easier to add optional attributes as well as control other behaviour (such as equality testing or ordering).
我更喜欢 typing.TypedDict
,这更适合与遗留代码库和 (JSON) 序列化一起使用.
I prefer either over typing.TypedDict
, which is more meant to be used with legacy codebases and (JSON) serialisations.
这篇关于如何在 Python 中将typing.Union 转换为其子类型之一?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!