三元运算符在Python中是如何实现的

2024-10-16 20:51:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道条件表达式(或三元运算符)在Python中是懒惰的。它们表示条件执行而不是条件选择。换言之,只有a或{}中的一个计算如下:

c = a if condition else b

我感兴趣的是这是如何在内部实现的。Python是否像下面这样转换为if语句,如果是,转换发生在什么阶段?在

^{pr2}$

或者三元运算符实际上是一个完全独立定义的独立表达式?如果是,我可以访问条件表达式的CPython代码吗?在

我已经看了下面这些解释了三元运算符的作用,但没有一个清楚地说明它们是如何实现的:


编辑:您可以假设CPython引用实现。在


Tags: if定义表达式运算符语句cpythoncondition条件
3条回答

Does Python convert to an if statement as below

差不多了。在

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)

该输出:

^{pr2}$

除了JUMP_FORWARD的位置和@L3viathan指出的另外一个{}之外,这些看起来几乎相同。在

我们也得到了几乎相同的执行时间(差别微乎其微):

from timeit import Timer

print(min(Timer(trenary).repeat(5000, 5000)))
print(min(Timer(normal_if).repeat(5000, 5000)))
# 0.0006442809999998023
# 0.0006442799999994975

至于发生这种转换时,我假设在“编译”到字节码的某个时候。在

什么

如果你在问什么,那么为了更好地理解它,你需要理解功能和程序之间的区别。一个可以转换为另一个,但两个都可以独立查看,您不必将其中一个转换为另一个才能理解它们。在

value_a if condition else value_b是函数型的,返回值value_a或{}。在

if condition then:
   do_a
else:
   do_b

是程序性的,它执行do_a或{}。在

注意:程序就是做,做这个,然后做那个,或者那个。功能是关于价值的,是这个还是那个。在

怎么回事

如果你在问怎么做,那么你需要看看其中一个实现的源代码。请注意,只要行为正确,每个实现不必以相同的方式执行。在

Python不需要转换任何东西,如果愿意的话也不能转换。在

使用language grammar将条件表达式解析为abstract syntax tree,然后将其编译为字节码。您可以使用^{} function生成AST:

>>> 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中为赋值生成的ast.IfExp()节点;这是用于条件表达式的专用节点。它有testbodyorelse部分来表示构成条件的3个表达式,真和假部分。这在^{} module Abstract Grammar section中有记录:

expr = [...]
     | [...]
     | IfExp(expr test, expr body, expr orelse)

这表明每个元素的类型是另一个expr表达式节点。在

然后将解析树编译为字节码,该字节码使用堆栈根据测试有条件地跳转到右边的部分;我们可以将ast.parse()生成的AST直接传递给^{} function,之后,^{} module让我们查看编译生成的字节码的友好形式:

^{pr2}$

因此,如果条件为false,解释器循环向前跳到指令8,否则执行指令4和指令6,指令6跳到指令10(因此超过else表达式)。最终结果是,指令4或指令8将一个新结果放在堆栈顶部,STORE_NAME移动到变量。在

一个if语句会导致一个不同的AST节点,而产生的字节码恰好非常相似,因为它也会使用跳转。但是编译器将它们视为不同的语法片段,并且to。在

表达式和语句是编程语言的两个非常不同的基本构造块。语句可以包含表达式,但表达式不能包含语句,只能包含其他表达式。和表达式可以生成一个值(供周围的语法使用),但语句不能。因此Python必须将条件表达式与语句处理得非常不同,因为语法解析器知道何时需要语句以及何时允许使用表达式。如果你把一个条件表达式转换成一个语句,你将永远不能使用这样的表达式作为一个更大的表达式的一部分!在

因为if语句不是表达式,它不会返回值(因为只有表达式才能产生值),因此生成的字节码不会在堆栈顶部生成一个值供周围的Python代码使用(没有c = if condition : ...)。if语句包含一个条件表达式和一个suite,这两个语句必须总是由更多的语句组成(有一个“expression statement”这样的东西可以让您在一个语句中只放一个表达式,例如1 + 1),这些语句可以“执行诸如赋值或从函数返回之类的事情,但是他们做的任何事都不会让if返回一些东西。在

这反映在if语句的AST节点定义中:

stmt =  [...]
      | [...]
      | If(expr test, stmt* body, stmt* orelse)

因此对于一个If节点,test是唯一的表达式节点,body和{}都由零个或多个语句组成。orelse部分将包含任何elif ...:测试作为进一步的If()节点,或任何其他类型的语句来形成一个无条件的else:。对于零个或多个元素,您不能期望一个单独的结果。在

所以这并不是CPython独有的,它适用于所有Python实现。Python语法不是实现细节。在

相关问题 更多 >