How is ternary operator implemented in Python
我理解条件表达式(或三元运算符)在Python中是懒惰的。它们表示条件执行,而不是条件选择。换言之,只有一个
1 | c = a if condition else b |
我感兴趣的是这是如何在内部实现的。python是否如下面所示转换为
1 2 3 4 | if condition: c = a else: c = b |
或者三元运算符实际上是一个完全独立定义的独立表达式?如果是,我可以访问条件表达式的cpython代码吗?
我看过下面解释三元运算符做什么的内容,但没有一个解释它们是如何实现的:
- python是否有三元条件运算符?
- 将简单的if-then-else语句放在一行上
- Python?(条件/三元)赋值运算符
- 是否有相当于c的?:"三元运算符?"
- 条件表达式
编辑:可以假设cpython引用实现。
python不需要转换任何东西,如果愿意的话也不能转换。
条件表达式通过使用语言语法解析为抽象语法树,然后将其编译为字节码。您可以使用
1 2 3 4 5 | >>> import ast >>> ast.parse('c = a if condition else b').body[0] # first statement in the tree <_ast.Assign object at 0x10f05c550> >>> ast.dump(ast.parse('c = a if condition else b').body[0]) "Assign(targets=[Name(id='c', ctx=Store())], value=IfExp(test=Name(id='condition', ctx=Load()), body=Name(id='a', ctx=Load()), orelse=Name(id='b', ctx=Load())))" |
注意ast中为赋值生成的
1
2
3 expr = [...]
| [...]
| IfExp(expr test, expr body, expr orelse)
这表明每个元素的类型是另一个
然后将解析树编译成字节码,该字节码使用堆栈根据测试有条件地跳转到右边的部分;我们可以将
1 2 3 4 5 6 7 8 9 10 | >>> import dis >>> dis.dis(compile(ast.parse('c = a if condition else b'), '', 'exec')) 1 0 LOAD_NAME 0 (condition) 2 POP_JUMP_IF_FALSE 8 4 LOAD_NAME 1 (a) 6 JUMP_FORWARD 2 (to 10) >> 8 LOAD_NAME 2 (b) >> 10 STORE_NAME 3 (c) 12 LOAD_CONST 0 (None) 14 RETURN_VALUE |
因此,如果条件为假,解释器循环将跳转到指令8,否则将执行指令4和6,指令6将跳转到指令10(因此将跳过
一条
表达式和语句是编程语言的两个非常不同的基本构造块。语句可以包含表达式,但表达式不能包含语句,只能包含其他表达式。表达式可以生成一个值(供周围的语法使用),但语句不能。因此,Python必须将条件表达式与语句区别对待,因为语法分析器知道何时需要语句,何时允许表达式。如果将条件表达式转换为语句,则永远无法将此类表达式用作更大表达式的一部分!
由于
这反映在
1
2
3 stmt = [...]
| [...]
| If(expr test, stmt* body, stmt* orelse)
因此,对于
所以这对cpython来说不是唯一的,这适用于所有的python实现。python语法不是实现细节。
Does Python convert to an if statement as below
几乎。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import dis def trenary(): x = 'a' if 1 == 1 else 'b' def normal_if(): if 1 == 1: c = 'a' else: c = 'b' print('trenary') dis.dis(trenary) print() print('normal if') dis.dis(normal_if) |
此输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | trenary 68 0 LOAD_CONST 1 (1) 2 LOAD_CONST 1 (1) 4 COMPARE_OP 2 (==) 6 POP_JUMP_IF_FALSE 12 8 LOAD_CONST 2 ('a') 10 JUMP_FORWARD 2 (to 14) >> 12 LOAD_CONST 3 ('b') >> 14 STORE_FAST 0 (x) 16 LOAD_CONST 0 (None) 18 RETURN_VALUE normal if 71 0 LOAD_CONST 1 (1) 2 LOAD_CONST 1 (1) 4 COMPARE_OP 2 (==) 6 POP_JUMP_IF_FALSE 14 72 8 LOAD_CONST 2 ('a') 10 STORE_FAST 0 (c) 12 JUMP_FORWARD 4 (to 18) 74 >> 14 LOAD_CONST 3 ('b') 16 STORE_FAST 0 (c) >> 18 LOAD_CONST 0 (None) 20 RETURN_VALUE |
这些看起来几乎一样,除了
我们还得到几乎相同的执行时间(差别可以忽略不计):
1 2 3 4 5 6 | from timeit import Timer print(min(Timer(trenary).repeat(5000, 5000))) print(min(Timer(normal_if).repeat(5000, 5000))) # 0.0006442809999998023 # 0.0006442799999994975 |
至于这种转换何时发生,我假设在"编译"到字节码的过程中。
什么
如果你在问什么,那么为了最好地理解它,你需要理解功能性和程序性之间的区别。一个可以转换为另一个,但两个都可以独立查看,您不必将一个转换为另一个来理解它们。
1 2 3 4 | if condition then: do_a else: do_b |
是程序性的,它执行
注意:程序就是这样做,做这个,然后做那个,或者那个。功能就是价值,是这个还是那个。
怎么如果您询问如何实现,那么您需要查看其中一个实现的源代码。请注意,只要行为正确,每个实现都不必以相同的方式进行。