将变量赋值给它自己的值是否会导致 Python 内存中的实际赋值?
Does an assignment of a variable to its own value result in an actual assignment in memory in Python?
如果我像这样(第 2 行)将一个变量赋给它自己的值(在之前赋值之后):
a_list = ['a', 'list']
a_list = a_list
这是编译成一个实际的赋值还是只是跳过了?
我问是因为我想知道以下两个代码片段中的后者是否会受到性能损失。
def foo(a_list: list = None):
if a_list is None:
a_list = ['default', 'list', 'values']
def foo(a_list: list = None):
a_list = ['default', 'list', 'values'] if a_list is None else a_list
您可以借助 dis
模块轻松自行检查。结果可能(并且很可能)在 python 个版本中发生变化:
https://docs.python.org/3/library/dis.html
import dis
>>> def foo(a_list: list = None):
... a_list = ['default', 'list', 'values'] if a_list is None else a_list
...
>>> dis.dis(foo)
2 0 LOAD_FAST 0 (a_list)
2 LOAD_CONST 0 (None)
4 COMPARE_OP 8 (is)
6 POP_JUMP_IF_FALSE 18
8 LOAD_CONST 1 ('default')
10 LOAD_CONST 2 ('list')
12 LOAD_CONST 3 ('values')
14 BUILD_LIST 3
16 JUMP_FORWARD 2 (to 20)
>> 18 LOAD_FAST 0 (a_list)
>> 20 STORE_FAST 0 (a_list)
22 LOAD_CONST 0 (None)
24 RETURN_VALUE
>>> def foo(a_list: list = None):
... if a_list is None:
... a_list = ['default', 'list', 'values']
...
>>> dis.dis(foo)
2 0 LOAD_FAST 0 (a_list)
2 LOAD_CONST 0 (None)
4 COMPARE_OP 8 (is)
6 POP_JUMP_IF_FALSE 18
3 8 LOAD_CONST 1 ('default')
10 LOAD_CONST 2 ('list')
12 LOAD_CONST 3 ('values')
14 BUILD_LIST 3
16 STORE_FAST 0 (a_list)
>> 18 LOAD_CONST 0 (None)
20 RETURN_VALUE
可以通过 dis.dis
调用自行验证两种方法生成的字节码。 (查看@petrch 的回答)
但是,与您的完整代码将使用的其他资源相比,身份分配的“成本”可以忽略不计,无论它们是什么:这种微优化不应该在 Python 代码:如果 CPU 周期计数到这个水平,您应该使用直接映射到 CPU ops 的语言,例如 C、GO 或 Rust。
也就是说,第一种形式,即使多加一行和缩进级别,也“更易于阅读”。我会选择第一种形式。单线可能会在“可能性能较低”的线程中转移直通列车这一事实是不值得的(正如你提出这个问题所证明的那样)
如果我像这样(第 2 行)将一个变量赋给它自己的值(在之前赋值之后):
a_list = ['a', 'list']
a_list = a_list
这是编译成一个实际的赋值还是只是跳过了?
我问是因为我想知道以下两个代码片段中的后者是否会受到性能损失。
def foo(a_list: list = None):
if a_list is None:
a_list = ['default', 'list', 'values']
def foo(a_list: list = None):
a_list = ['default', 'list', 'values'] if a_list is None else a_list
您可以借助 dis
模块轻松自行检查。结果可能(并且很可能)在 python 个版本中发生变化:
https://docs.python.org/3/library/dis.html
import dis
>>> def foo(a_list: list = None):
... a_list = ['default', 'list', 'values'] if a_list is None else a_list
...
>>> dis.dis(foo)
2 0 LOAD_FAST 0 (a_list)
2 LOAD_CONST 0 (None)
4 COMPARE_OP 8 (is)
6 POP_JUMP_IF_FALSE 18
8 LOAD_CONST 1 ('default')
10 LOAD_CONST 2 ('list')
12 LOAD_CONST 3 ('values')
14 BUILD_LIST 3
16 JUMP_FORWARD 2 (to 20)
>> 18 LOAD_FAST 0 (a_list)
>> 20 STORE_FAST 0 (a_list)
22 LOAD_CONST 0 (None)
24 RETURN_VALUE
>>> def foo(a_list: list = None):
... if a_list is None:
... a_list = ['default', 'list', 'values']
...
>>> dis.dis(foo)
2 0 LOAD_FAST 0 (a_list)
2 LOAD_CONST 0 (None)
4 COMPARE_OP 8 (is)
6 POP_JUMP_IF_FALSE 18
3 8 LOAD_CONST 1 ('default')
10 LOAD_CONST 2 ('list')
12 LOAD_CONST 3 ('values')
14 BUILD_LIST 3
16 STORE_FAST 0 (a_list)
>> 18 LOAD_CONST 0 (None)
20 RETURN_VALUE
可以通过 dis.dis
调用自行验证两种方法生成的字节码。 (查看@petrch 的回答)
但是,与您的完整代码将使用的其他资源相比,身份分配的“成本”可以忽略不计,无论它们是什么:这种微优化不应该在 Python 代码:如果 CPU 周期计数到这个水平,您应该使用直接映射到 CPU ops 的语言,例如 C、GO 或 Rust。
也就是说,第一种形式,即使多加一行和缩进级别,也“更易于阅读”。我会选择第一种形式。单线可能会在“可能性能较低”的线程中转移直通列车这一事实是不值得的(正如你提出这个问题所证明的那样)