通过分解的媒介进行解释:
>>> dis.dis('''greeting = 'hello'
... greeting = f'y{greeting[1:len(greeting)]}'
... ''')
1 0 LOAD_CONST 0 ('hello')
2 STORE_NAME 0 (greeting)
2 4 LOAD_CONST 1 ('y')
6 LOAD_NAME 0 (greeting)
8 LOAD_CONST 2 (1)
10 LOAD_NAME 1 (len)
12 LOAD_NAME 0 (greeting)
14 CALL_FUNCTION 1
16 BUILD_SLICE 2
18 BINARY_SUBSCR
20 FORMAT_VALUE 0
22 BUILD_STRING 2
24 STORE_NAME 0 (greeting)
26 LOAD_CONST 3 (None)
28 RETURN_VALUE
最左边的数字表示特定行字节码的起始位置。第1行非常简单,所以我将解释第2行。
正如您可能注意到的,您的f字符串在编译后无法保存;它变成了一堆原始操作码,将常量段的加载与格式占位符的计算混合在一起,最终导致堆栈顶部出现构成最终字符串的所有片段。当它们都在堆栈上时,它会将所有的片段放在一起,最后用
BUILD_STRING 2
(上面写着“从堆栈中取出最上面的两个值,并将它们组合成一个字符串”)。
greeting
只是一个有约束力的名字。它实际上并不包含一个值,只是对它当前绑定到的任何对象的引用。原始引用被推到堆栈上(使用
LOAD_NAME
)完全是在
STORE_NAME
这会弹出堆栈顶部并重新绑定
招呼
.
简而言之,它之所以有效,是因为
招呼
被替换时不再需要;它被用来生成新字符串,然后被丢弃,取而代之的是新字符串。