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

How does Python's re-declaration of variables work internally?

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

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

除了解释之外,我也非常感谢一些上下文。我知道字符串是不可变的,但是其他类型(如浮点数和整数)呢? 我是否了解 python 的内部运作方式重要吗?另外,如果 Python 在内部工作,哪里是了解更多信息的好地方?

希望我的问题很清楚。

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

浮点数和整数也是不可变的。只有列表和字典是可变的。实际上,在任何情况下都不清楚如何修改整数对象。您不能引用对象的内部。请务必记住,在这种情况下:

i = 3
j = 4
i = i + j

最后一行只是创建了一个新的 integer/float 对象并将其绑定到 i。 None 尝试修改整数对象 3

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

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

通过反汇编的解释:

>>> 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 行很漂亮 self-explanatory,所以我将解释第 2 行。

您可能会注意到,您的 f-string 无法通过编译;它变成了一堆原始操作码,混合了常量段的加载和格式化占位符的评估,最终导致堆栈被构成最终字符串的所有片段所覆盖。当它们都在堆栈上时,它将所有片段放在最后 BUILD_STRING 2 (表示“从堆栈中取出顶部的两个值并将它们组合成一个字符串”)。

greeting 只是一个持有绑定的名称。它实际上没有值,只是对当前绑定到的任何对象的引用。并且原始引用完全在弹出堆栈顶部并重新绑定 greeting.

STORE_NAME 之前被推入堆栈(使用 LOAD_NAME

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