使用类型注释来缩小已声明 Python 变量的类型
Use type comments to narrow typing of already declared Python variable
如何使用 Python 中的类型注释来更改或缩小已声明变量的类型,使 pycharm
或其他类型感知系统能够理解新的类型类型。
例如,我可能有两个 classes:
class A:
is_b = False
...
class B(A):
is_b = True
def flummox(self):
return '?'
和其他地方的另一个功能:
def do_something_to_A(a_in: A):
...
if a_in.is_b:
assert isinstance(a_in, B) # THIS IS THE LINE...
a_in.flummox()
只要我有assert
声明,PyCharm就会明白我把a_in
缩小为class B,而不是抱怨.flummox()
。没有它,就会出现errors/warnings之类的a_in has no method flummox
。
我的问题是,是否有 PEP 484(或后继者)方式表明 a_in
(最初可能是 A 或 B 类型或其他类型)现在是 B 类型 没有 assert 语句。语句 b_in : B = a_in
也给出了类型错误。
在 TypeScript 中我可以这样做:
if a_in.is_b:
const b_in = <B><any> a_in;
b_in.flummox()
// or
if a_in.is_b:
(a_in as B).flummox()
我不想使用 assert 行的主要原因有两个:(1) 速度对这部分代码非常重要,并且每次该行都需要额外的 is_instance
调用运行 太慢了,并且 (2) 项目代码风格禁止裸断言语句。
只要您使用的是 Python 3.6+,您就可以任意 "re-annotate" 变量的类型,使用与 "declare" 变量类型相同的语法未初始化的变量 (PEP 526).
在您提供的示例中,以下代码段具有您期望的行为:
def do_something_to_A(a_in: A):
...
if a_in.is_b:
a_in: B
a_in.flummox()
我已经测试 PyCharm 2019.2 正确检测到此技术。
值得注意的是,这不会产生任何运行时成本,因为使用或不使用此添加的注释语句都会生成相同的字节码。给定以下定义,
def do_something_with_annotation(a_in: A):
if a_in.is_b:
a_in: B
a_in.flummox()
def do_something_without_annotation(a_in: A):
if a_in.is_b:
a_in.flummox()
dis
生成以下字节码:
>>> dis.dis(do_something_with_annotation)
3 0 LOAD_FAST 0 (a_in)
2 LOAD_ATTR 0 (is_b)
4 POP_JUMP_IF_FALSE 14
5 6 LOAD_FAST 0 (a_in)
8 LOAD_ATTR 1 (flummox)
10 CALL_FUNCTION 0
12 POP_TOP
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis(do_something_without_annotation)
3 0 LOAD_FAST 0 (a_in)
2 LOAD_ATTR 0 (is_b)
4 POP_JUMP_IF_FALSE 14
4 6 LOAD_FAST 0 (a_in)
8 LOAD_ATTR 1 (flummox)
10 CALL_FUNCTION 0
12 POP_TOP
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
作为旁注,您还可以通过使用 -O
标志调用解释器来在生产环境中保留断言语句和 disable assertions。这可能会或可能不会被您的同事认为更具可读性,具体取决于他们对 Python.
中类型提示的熟悉程度
如何使用 Python 中的类型注释来更改或缩小已声明变量的类型,使 pycharm
或其他类型感知系统能够理解新的类型类型。
例如,我可能有两个 classes:
class A:
is_b = False
...
class B(A):
is_b = True
def flummox(self):
return '?'
和其他地方的另一个功能:
def do_something_to_A(a_in: A):
...
if a_in.is_b:
assert isinstance(a_in, B) # THIS IS THE LINE...
a_in.flummox()
只要我有assert
声明,PyCharm就会明白我把a_in
缩小为class B,而不是抱怨.flummox()
。没有它,就会出现errors/warnings之类的a_in has no method flummox
。
我的问题是,是否有 PEP 484(或后继者)方式表明 a_in
(最初可能是 A 或 B 类型或其他类型)现在是 B 类型 没有 assert 语句。语句 b_in : B = a_in
也给出了类型错误。
在 TypeScript 中我可以这样做:
if a_in.is_b:
const b_in = <B><any> a_in;
b_in.flummox()
// or
if a_in.is_b:
(a_in as B).flummox()
我不想使用 assert 行的主要原因有两个:(1) 速度对这部分代码非常重要,并且每次该行都需要额外的 is_instance
调用运行 太慢了,并且 (2) 项目代码风格禁止裸断言语句。
只要您使用的是 Python 3.6+,您就可以任意 "re-annotate" 变量的类型,使用与 "declare" 变量类型相同的语法未初始化的变量 (PEP 526).
在您提供的示例中,以下代码段具有您期望的行为:
def do_something_to_A(a_in: A):
...
if a_in.is_b:
a_in: B
a_in.flummox()
我已经测试 PyCharm 2019.2 正确检测到此技术。
值得注意的是,这不会产生任何运行时成本,因为使用或不使用此添加的注释语句都会生成相同的字节码。给定以下定义,
def do_something_with_annotation(a_in: A):
if a_in.is_b:
a_in: B
a_in.flummox()
def do_something_without_annotation(a_in: A):
if a_in.is_b:
a_in.flummox()
dis
生成以下字节码:
>>> dis.dis(do_something_with_annotation)
3 0 LOAD_FAST 0 (a_in)
2 LOAD_ATTR 0 (is_b)
4 POP_JUMP_IF_FALSE 14
5 6 LOAD_FAST 0 (a_in)
8 LOAD_ATTR 1 (flummox)
10 CALL_FUNCTION 0
12 POP_TOP
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis(do_something_without_annotation)
3 0 LOAD_FAST 0 (a_in)
2 LOAD_ATTR 0 (is_b)
4 POP_JUMP_IF_FALSE 14
4 6 LOAD_FAST 0 (a_in)
8 LOAD_ATTR 1 (flummox)
10 CALL_FUNCTION 0
12 POP_TOP
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
作为旁注,您还可以通过使用 -O
标志调用解释器来在生产环境中保留断言语句和 disable assertions。这可能会或可能不会被您的同事认为更具可读性,具体取决于他们对 Python.