在 python 中评估?
Evaluation in python?
available_items = {"health potion": 10, "cake of the cure": 5, "green elixir": 20, "strength sandwich": 25, "stamina grains": 15, "power stew": 30}
health_points = 20
health_points += available_items.pop("stamina grains")
当我 运行 此代码时,添加了键值 "stamina grains" 并从字典 available_items
中删除了耐力颗粒 available_items
。
但是 Python 从左到右评估表达式,因此它应该首先删除键 "stamina grains" 因此不应向 health_points
.
添加任何内容
我对 Python 如何计算表达式感到困惑。有人可以澄清一下并给我一些关于 Python 如何计算表达式的资源吗?
CPython 作为 stack machine 实现。如果您想准确查看子表达式的计算顺序,反汇编它们会很有帮助:
>>> from dis import dis
>>> dis('''
... available_items = {"health potion": 10, "cake of the cure": 5, "green elixir": 20, "strength sandwich": 25, "stamina grains": 15, "power stew": 30}
...
... health_points = 20
...
... health_points += available_items.pop("stamina grains")
... ''')
2 0 LOAD_CONST 0 (10)
2 LOAD_CONST 1 (5)
4 LOAD_CONST 2 (20)
6 LOAD_CONST 3 (25)
8 LOAD_CONST 4 (15)
10 LOAD_CONST 5 (30)
12 LOAD_CONST 6 (('health potion', 'cake of the cure', 'green elixir', 'strength sandwich', 'stamina grains', 'power stew'))
14 BUILD_CONST_KEY_MAP 6
16 STORE_NAME 0 (available_items)
4 18 LOAD_CONST 2 (20)
20 STORE_NAME 1 (health_points)
6 22 LOAD_NAME 1 (health_points)
24 LOAD_NAME 0 (available_items)
26 LOAD_METHOD 2 (pop)
28 LOAD_CONST 7 ('stamina grains')
30 CALL_METHOD 1
32 INPLACE_ADD
34 STORE_NAME 1 (health_points)
36 LOAD_CONST 8 (None)
38 RETURN_VALUE
虽然子表达式(大部分)从左到右求值,但运算符优先级和括号可以改变这一点。赋值是一个语句,而不是表达式。即使 +=
在 .pop()
的左侧,您也可以看到调用发生在编译后的字节码中的赋值之前。
请注意,(pop)
调用将其 return 值压入堆栈中的 CALL_METHOD
指令,因此它可以被 INPLACE_ADD
使用。那时,该值未在字典中引用,仅在堆栈中引用,但该值从未丢失。加法的结果可用于之后的 STORE_NAME
指令。
来自first Google result搜索"Python+dictionary +pop"(重点是我的):
The pop()
method removes and returns an element from a dictionary having the given key.
所以,确实pop
动作是第一个执行的,从字典中删除元素也是正确的,但它也returns 该值,用于更新 healt_points
变量。
详细,根据evaluation order table:
Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.
所以,考虑表达式
health_points = health_points + available_items.pop("stamina grains")
- 我们有一个作业,所以首先计算右边:
health_points + available_items.pop("stamina grains")
- 右边,从左到右计算:
health_points
先计算,它的值为20
- 现在评估
available_items.pop("stamina grains")
。为 available_items
字典 调用 pop
方法
- 找到键
"stamina grains"
,返回其值(15)
- 作为副作用,
pop
从字典中删除了 "stamina grains"
。无论如何都会返回值 15:它只是一个表示方法结果的整数。不再受限于字典元素的存在
- 表达式现在是
health_points = 20 + 15
。右侧评估是整数 35,现在可以将其分配给 health_points
。这完成了左侧评估
如果你看这里:Operator precedence,你可以看到 "call" 靠近 table 的底部,所以它首先被执行。执行完第一步后,您可以将语句重写为:
health_points += 15
.
再高一点就是加法,接下来执行(+=
是加法的简写:health_points = health_points + available_items.pop("stamina grains")
)。最上面是赋值,所以这是最后执行的。导致 health_points == 35
.
available_items = {"health potion": 10, "cake of the cure": 5, "green elixir": 20, "strength sandwich": 25, "stamina grains": 15, "power stew": 30}
health_points = 20
health_points += available_items.pop("stamina grains")
当我 运行 此代码时,添加了键值 "stamina grains" 并从字典 available_items
中删除了耐力颗粒 available_items
。
但是 Python 从左到右评估表达式,因此它应该首先删除键 "stamina grains" 因此不应向 health_points
.
我对 Python 如何计算表达式感到困惑。有人可以澄清一下并给我一些关于 Python 如何计算表达式的资源吗?
CPython 作为 stack machine 实现。如果您想准确查看子表达式的计算顺序,反汇编它们会很有帮助:
>>> from dis import dis
>>> dis('''
... available_items = {"health potion": 10, "cake of the cure": 5, "green elixir": 20, "strength sandwich": 25, "stamina grains": 15, "power stew": 30}
...
... health_points = 20
...
... health_points += available_items.pop("stamina grains")
... ''')
2 0 LOAD_CONST 0 (10)
2 LOAD_CONST 1 (5)
4 LOAD_CONST 2 (20)
6 LOAD_CONST 3 (25)
8 LOAD_CONST 4 (15)
10 LOAD_CONST 5 (30)
12 LOAD_CONST 6 (('health potion', 'cake of the cure', 'green elixir', 'strength sandwich', 'stamina grains', 'power stew'))
14 BUILD_CONST_KEY_MAP 6
16 STORE_NAME 0 (available_items)
4 18 LOAD_CONST 2 (20)
20 STORE_NAME 1 (health_points)
6 22 LOAD_NAME 1 (health_points)
24 LOAD_NAME 0 (available_items)
26 LOAD_METHOD 2 (pop)
28 LOAD_CONST 7 ('stamina grains')
30 CALL_METHOD 1
32 INPLACE_ADD
34 STORE_NAME 1 (health_points)
36 LOAD_CONST 8 (None)
38 RETURN_VALUE
虽然子表达式(大部分)从左到右求值,但运算符优先级和括号可以改变这一点。赋值是一个语句,而不是表达式。即使 +=
在 .pop()
的左侧,您也可以看到调用发生在编译后的字节码中的赋值之前。
请注意,(pop)
调用将其 return 值压入堆栈中的 CALL_METHOD
指令,因此它可以被 INPLACE_ADD
使用。那时,该值未在字典中引用,仅在堆栈中引用,但该值从未丢失。加法的结果可用于之后的 STORE_NAME
指令。
来自first Google result搜索"Python+dictionary +pop"(重点是我的):
The
pop()
method removes and returns an element from a dictionary having the given key.
所以,确实pop
动作是第一个执行的,从字典中删除元素也是正确的,但它也returns 该值,用于更新 healt_points
变量。
详细,根据evaluation order table:
Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.
所以,考虑表达式
health_points = health_points + available_items.pop("stamina grains")
- 我们有一个作业,所以首先计算右边:
health_points + available_items.pop("stamina grains")
- 右边,从左到右计算:
health_points
先计算,它的值为20 - 现在评估
available_items.pop("stamina grains")
。为available_items
字典 调用 - 找到键
"stamina grains"
,返回其值(15) - 作为副作用,
pop
从字典中删除了"stamina grains"
。无论如何都会返回值 15:它只是一个表示方法结果的整数。不再受限于字典元素的存在 - 表达式现在是
health_points = 20 + 15
。右侧评估是整数 35,现在可以将其分配给health_points
。这完成了左侧评估
pop
方法
如果你看这里:Operator precedence,你可以看到 "call" 靠近 table 的底部,所以它首先被执行。执行完第一步后,您可以将语句重写为:
health_points += 15
.
再高一点就是加法,接下来执行(+=
是加法的简写:health_points = health_points + available_items.pop("stamina grains")
)。最上面是赋值,所以这是最后执行的。导致 health_points == 35
.