如何解决类型和类型的Python类型提示之间的区别?
今天,我遇到了一个用type
提示的函数类型。
我已经进行了一些有关何时应该使用type
或Type
键入提示的研究,但找不到令人满意的答案。从我的研究看来,两者之间有些重叠。
我的问题:
-
type
和Type
有什么区别? - 有什么用例示例说明何时使用
type
与Type
?
研究
看Type
(from typing
tag 3.7.4.3
)的来源,我可以看到:
# Internal type variable used for Type[]. CT_co = TypeVar('CT_co',covariant=True,bound=type) # This is not a real generic class. Don't use outside annotations. class Type(Generic[CT_co],extra=type): """A special construct usable to annotate class objects. ```
看起来Type
可能只是type
的别名,但它支持Generic
参数化。这是正确的吗?
示例
以下是使用Python==3.8.5
和mypy==0.782
制作的一些示例代码:
from typing import Type
def foo(val: type) -> None:
reveal_type(val) # mypy output: Revealed type is 'builtins.type'
def bar(val: Type) -> None:
reveal_type(val) # mypy output: Revealed type is 'Type[Any]'
class Baz:
pass
foo(type(bool))
foo(Baz)
foo(Baz()) # error: Argument 1 to "foo" has incompatible type "Baz"; expected "type"
bar(type(bool))
bar(Baz)
bar(Baz()) # error: Argument 1 to "bar" has incompatible type "Baz"; expected "Type[Any]"
很明显mypy
认识到差异。
解决方法
type
is a metaclass.就像对象实例是类的实例一样,类是元类的实例。
@echo off
setlocal
set DATA=%DATE:~10,4%%DATE:~4,2%%DATE:~7,2%_%TIME:~0,2%h%TIME:~3,2%m
set HOUR=%TIME:~0,2%
if "%HOUR:~0,1%" == " " set DATA=%DATE:~10,2%_%TIME:~1,1%h%TIME:~3,2%m
@Set "LIST=serversRDPok.txt"
@Set "USER=%USERDOMAIN%\%USERNAME%"
@Set "PASSWORD=password123"
@Set "RESULTS=SQLserverVersion_MR_PRD_%DATA%.csv"
@"%__APPDIR__%wbem\WMIC.exe" /FailFast:On /Node:"@%LIST%" /Output:"%RESULTS%" /Password:"%PASSWORD%" /User:"%USER%" process call create "sqlcmd -? | find "Version"" /Format:CSV
endlocal
pause
是一个注释,用于告知类型检查器,无论使用该注释的位置,都是在处理该类对象本身,而不是该类对象的实例。
它们之间有几种关联方式。
- 将
Type
应用于自变量时,带注释的返回类型为type
。这与应用于参数(例如Type
)的list
具有带注释的返回类型list((1,2))
相同。在以下位置使用reveal_type:
List
我们要问的是reveal_type(type(1))
返回值为1时推断出的类型注释是什么。答案是type
,更具体地说是Type
。
-
Type[Literal[1]]
是类型检查时间构造,Type
是运行时构造。这具有多种含义,我将在后面解释。
进入示例,
type
我们没有将class Type(Generic[CT_co],extra=type):
...
注释为extra
,而是将具有值type
的关键字参数extra
传递给type
的元类。有关此构造的更多示例,请参见Class-level Keyword Arguments。请注意,Type
与extra=type
有很大不同:一个是在运行时分配值,另一个是在类型检查时使用类型提示进行注释。
现在介绍有趣的部分:如果extra: type
能够同时对两者进行成功的类型检查,为什么还要在另一个上使用呢?答案在于mypy
是类型检查时间的构造,它与类型生态系统的集成度更高。给出以下示例:
Type
from typing import Type,TypeVar
T = TypeVar("T")
def smart(t: Type[T],v: T) -> T:
return v
def naive(t: type,v: T) -> T:
return v
v1: int = smart(int,1) # Success.
v2: int = smart(str,1) # Error.
v3: int = naive(int,1) # Success.
v4: int = naive(str,1) # Success.
,v1
和v3
类型检查成功。您可以看到v4
中的v4
是误报,因为naive
的类型是1
,而不是int
。但是因为您无法参数化str
元类(它不是type
),所以我们无法获得Generic
所具有的安全性。
我认为这更多是一种语言限制。您可以看到PEP 585试图弥合相同的差距,但有smart
/ list
。归根结底,想法还是一样:小写版本是运行时类,大写版本是类型注释。两者可以重叠,但是两者都有一些独有的功能。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。