关于类型类型的 Mypy 断言
Mypy Assertions on the Types of Types
在Python中,我们可以这样给一个变量赋值类型,并通过mypy的typecheck:
from typing import Type, Union
class Foo:
pass
MyType: Type[Foo] = Foo
同样,我们也可以使用Union
进行打字
from typing import Type, Union
class Foo:
pass
class Bar:
pass
def func(is_bar: bool) -> Union[Type[Foo], Type[Bar]]:
if is_bar:
return Bar
else:
return Foo
知道 is_bar
的值,在调用 func
进行类型缩小后使用断言是完全合理的。
但是,断言似乎对 MyType 根本不起作用,因为 mypy 对以下代码示例给出错误:
MyType = func(True)
assert MyType is Bar
# `assert MyType is Type[Bar]` gives the same result
Test: Bar = MyType # Incompatible types in assignment (expression
# has type "Union[Type[Foo], Type[Bar]]",
# variable has type "Bar")
cast
和 isinstance
也不起作用。
MyType = func(True)
cast(Type[Bar], MyType)
Test: Bar = MyType # MyType is considered `Type[Bar] | Type[Foo]`
MyType = func(True)
assert isintance(MyType, Type[Bar])
Test: Bar = MyType # MyType is considered `Type[Bar] | Type[Foo]`
我的问题是:如何对类型的类型进行类型缩小?还是mypy的限制?如果是这样,解决方法是什么?
相关:
cast
助手 returns 它的约束参数,它实际上并没有 改变 它的参数是约束。
cast
到所需的 Type[...]
并分配或使用结果:
Test = cast(Type[Bar], MyType)
reveal_type(Test) # note: Revealed type is "Type[so_testbed.Bar]"
另一种避免必须使用 typing.cast
或 isinstance
的解决方案是使用 typing.overload
,它允许您注册单个函数的多个签名。所有用 @typing.overload
装饰的函数在运行时都会被忽略,以支持“具体”实现,因此这些函数的主体可以只是一个文字省略号。通过组合 typing.overload
和 typing.Literal
,我们可以注册函数的一个签名,如果传入值 True
,如果传入值 False
则注册另一个:
from typing import Type, Union, overload, Literal
class Foo:
pass
class Bar:
pass
@overload
def func(is_bar: Literal[True]) -> Type[Bar]: ...
@overload
def func(is_bar: Literal[False]) -> Type[Foo]: ...
def func(is_bar: bool) -> Union[Type[Foo], Type[Bar]]:
if is_bar:
return Bar
else:
return Foo
test: Type[Bar] = func(True)
test2: Type[Foo] = func(False)
test3: Bar = func(True)()
test4: Foo = func(False)()
类型检查没问题。
在Python中,我们可以这样给一个变量赋值类型,并通过mypy的typecheck:
from typing import Type, Union
class Foo:
pass
MyType: Type[Foo] = Foo
同样,我们也可以使用Union
进行打字
from typing import Type, Union
class Foo:
pass
class Bar:
pass
def func(is_bar: bool) -> Union[Type[Foo], Type[Bar]]:
if is_bar:
return Bar
else:
return Foo
知道 is_bar
的值,在调用 func
进行类型缩小后使用断言是完全合理的。
但是,断言似乎对 MyType 根本不起作用,因为 mypy 对以下代码示例给出错误:
MyType = func(True)
assert MyType is Bar
# `assert MyType is Type[Bar]` gives the same result
Test: Bar = MyType # Incompatible types in assignment (expression
# has type "Union[Type[Foo], Type[Bar]]",
# variable has type "Bar")
cast
和 isinstance
也不起作用。
MyType = func(True)
cast(Type[Bar], MyType)
Test: Bar = MyType # MyType is considered `Type[Bar] | Type[Foo]`
MyType = func(True)
assert isintance(MyType, Type[Bar])
Test: Bar = MyType # MyType is considered `Type[Bar] | Type[Foo]`
我的问题是:如何对类型的类型进行类型缩小?还是mypy的限制?如果是这样,解决方法是什么?
相关:
cast
助手 returns 它的约束参数,它实际上并没有 改变 它的参数是约束。
cast
到所需的 Type[...]
并分配或使用结果:
Test = cast(Type[Bar], MyType)
reveal_type(Test) # note: Revealed type is "Type[so_testbed.Bar]"
另一种避免必须使用 typing.cast
或 isinstance
的解决方案是使用 typing.overload
,它允许您注册单个函数的多个签名。所有用 @typing.overload
装饰的函数在运行时都会被忽略,以支持“具体”实现,因此这些函数的主体可以只是一个文字省略号。通过组合 typing.overload
和 typing.Literal
,我们可以注册函数的一个签名,如果传入值 True
,如果传入值 False
则注册另一个:
from typing import Type, Union, overload, Literal
class Foo:
pass
class Bar:
pass
@overload
def func(is_bar: Literal[True]) -> Type[Bar]: ...
@overload
def func(is_bar: Literal[False]) -> Type[Foo]: ...
def func(is_bar: bool) -> Union[Type[Foo], Type[Bar]]:
if is_bar:
return Bar
else:
return Foo
test: Type[Bar] = func(True)
test2: Type[Foo] = func(False)
test3: Bar = func(True)()
test4: Foo = func(False)()
类型检查没问题。