Py学习  »  Python

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

il velan • 3 年前 • 1107 次点击  

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

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

除了解释,我也非常感谢一些上下文。我知道字符串是不可变的,但其他类型如浮点数和整数呢? 我是否理解python内部的运行方式重要吗?此外,如果Python能够在内部工作,那么哪里是了解Python如何工作的好地方呢?

希望我的问题清楚。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/133356
 
1107 次点击  
文章 [ 2 ]  |  最新文章 3 年前
Tim Roberts
Reply   •   1 楼
Tim Roberts    3 年前

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

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

i = 3
j = 4
i = i + j

最后一行只是创建一个新的整数/浮点对象并将其绑定到 i 。所有这些都不会试图修改integer对象 3 .

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

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

ShadowRanger
Reply   •   2 楼
ShadowRanger    3 年前

通过分解的媒介进行解释:

>>> 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 这会弹出堆栈顶部并重新绑定 招呼 .

简而言之,它之所以有效,是因为 招呼 被替换时不再需要;它被用来生成新字符串,然后被丢弃,取而代之的是新字符串。