gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 21:27:46 24 4
gpt4 key购买 nike

我知道条件表达式(或三元运算符)在 Python 中是惰性的。它们代表有条件的执行,而不是有条件的选择。换句话说,只有 ab 中的一个被评估如下:

c = a if condition else b

我想知道的是如何这是在内部实现的。 Python 是否转换为如下所示的 if 语句?如果是,这种转换发生在哪个阶段?

if condition:
c = a
else:
c = b

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

我看过以下解释什么三元运算符的作用,但没有一个明确说明如何它们是如何实现的:


编辑:您可以采用 CPython 引用实现。

最佳答案

Python 不需要转换任何东西,如果它想的话也不能。

使用 language grammar 解析条件表达式进入abstract syntax tree ,然后将其编译为字节码。您可以使用 ast.parse() 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 部分来表示构成条件、true 和 false 部分的 3 个表达式。这记录在 ast module Abstract Grammar section 中:

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

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

然后解析树被编译为字节码,使用堆栈根据测试有条件地跳转到正确的部分;我们可以将 ast.parse() 生成的 AST 直接传递给 compile() function ,之后是 dis module让我们看看编译生成的字节码的一种人性化形式:

>>> 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(因此经过 else 表达式)。最终结果是指令 4 或指令 8 将新结果放在堆栈顶部,以便 STORE_NAME 移动到变量。

if 语句导致不同的 AST 节点,并且生成的字节码碰巧非常相似,因为它也会使用跳转。但编译器将它们视为不同的语法片段,必须这样做。

表达式和语句是编程语言两个截然不同的基本构建 block 。语句可以包含表达式,但表达式不能包含语句,只能包含其他表达式。表达式可以产生一个值(供周围语法使用),但语句不能。所以 Python 必须以非常不同的方式对待条件表达式和语句,因为语法解析器知道什么时候需要语句以及什么时候允许表达式。如果将条件表达式转换为语句,则永远无法将这样的表达式用作更大表达式的一部分!

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

这反射(reflect)在 if 语句的 AST 节点定义中:

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

所以对于一个If节点,test是唯一的表达式节点,bodyorelse都包含零个或多个 语句。 orelse 部分将包含任何 elif ...: 测试作为进一步的 If() 节点,或任何其他类型的语句以形成无条件其他:。对于零个或多个元素,您不能期待一个结果。

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

关于python - 三元运算符在Python中是如何实现的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52201848/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com