Python 对变量的重新声明如何在内部工作?



我对Python相当陌生,所以这对一些人来说可能是一个微不足道的问题。但是我很好奇,当你将一个新对象绑定到一个变量时,Python内部是如何工作的,它引用了绑定到相同变量名的前一个对象。请参阅下面的代码作为示例-我理解python打破了与原始对象'hello'的绑定,将其绑定到新对象,但这里的事件顺序是什么?python如何打破与原始对象的联系,同时又引用它?

greeting = 'hello'
greeting = f'y{greeting[1:len(greeting)]}' 

除了解释,我也会非常欣赏一些上下文。我知道字符串是不可变的,但其他类型,如浮点数和整数呢?我是否理解python内部是如何运作的重要吗?另外,如果有的话,哪里是了解更多Python内部工作原理的好地方呢?

希望我的问题讲清楚了。

通过拆解的媒介说明:

>>> 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-string不能在编译后存活;它变成了一堆原始的操作码,混合了常量段的加载和格式化占位符的计算,最终导致堆栈被构成最终字符串的所有片段覆盖。当它们都在堆栈上时,它然后用BUILD_STRING 2把所有的片段放在一起(它说"从堆栈中取出前两个值并将它们组合成一个字符串")。

greeting只是一个包含绑定的名称。它实际上并没有保存一个值,只是一个指向它当前绑定的对象的引用。并且在STORE_NAME之前,原始引用完全被推到堆栈上(与LOAD_NAME一起),CC_4弹出堆栈顶部并重新绑定greeting

简而言之,它工作的原因是greeting的值在它被替换时不再需要;它用于生成新字符串,然后被丢弃,以支持新字符串。

在第二行中,Python计算赋值语句的右侧,它创建了一个使用greeting旧绑定的字符串。只有在对表达式求值之后,它才处理赋值操作符,将该字符串绑定到名称。都是线性的

浮点数和整数也是不可变的。只有列表和字典是可变的。实际上,在任何情况下如何修改整数对象都不清楚。你不能指向物体的内部。重要的是要记住,在这种情况下:

i = 3
j = 4
i = i + j

最后一行只是创建了一个新的整型/浮点型对象,并将其绑定到i

我写了这篇文章,试图描述Python对象和我们使用的名称之间的区别:

https://github.com/timrprobocom/documents/blob/main/UnderstandingPythonObjects.md

最新更新