[如何使用Python中的类型注释来改变或缩小已经声明的变量的类型,以使pycharm
或其他类型识别系统理解这种新类型。
例如,我可能有两个类:
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
的范围缩小到了B类,而没有抱怨.flummox()
。没有它,将出现错误/警告,例如a_in has no method flummox
。
[我的问题是,有没有PEP 484(或后继)方式显示a_in
(最初可能是A或B类型或其他类型)现在是B类型没有断言语句。语句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()
我不想使用断言行的两个主要原因是(1)速度对于这部分代码非常重要,并且每次运行该行时都要进行一次额外的is_instance
调用,这也会使其速度变慢(2)一种项目代码样式,它禁止使用裸断言语句。
只要您使用的是Python 3.6+,就可以使用与“声明”变量类型而无需初始化的语法相同的语法任意地“重新注释”变量的类型。
在您提供的示例中,以下代码片段具有您期望的行为:
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.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
标志调用解释器,将断言语句和disable assertions保留在生产环境中。您的同事可能会或可能不会认为这更易读,这取决于他们对Python中类型提示的熟悉程度。