缺少声明语句的情况——变量,对象和引用

未匹配的标注

本书到目前为止的许多例子中,当在Python中运行赋值语句如 a=3时,即使从未告诉Python将名称a作为变量使用,或a应该代表整数对象,也可以工作。在Python语言中,这些都以一种非常自然的方式发展,如下:

变量创建

​ 变量(也就是:名称),如a,当代码首次给其赋值时被创建。未来的赋值会改变已创建名称的值。技术上讲,Python在代码运行前检测到一些名称,但可以将其想为初始赋值创建了变量。

变量类型

​ 变量从没有任何类型信息或与其有关的限制。类型概念和对象联系在一起,而非名称。变量本质上是通用的,它们总是简单地在某个特殊的时间点引用某个特殊对象。

变量使用

​ 当变量出现在表达式中时,它立即被其当前引用的对象替换掉,不管该对象可能是什么。而且,所有对象在能被使用前必须被明确地赋值;引用未赋值变量会导致错误。

总的来说,变量在赋值时被创建,能引用任何类型的对象,且在被引用前必须被赋值。这意味着从不需要声明脚本使用的名称,但必须在能更新它们前先初始化:比如,在能给计数器增加计数前,必须将其初始化为0。

这种动态类型模型和传统语言的类型模型差异很大。当开始学习这个模型时,如果明白名称和对象之间的差异就会更容易理解。比如,当如下为变量赋值时:

>>> a = 3 # 为对象分配名称

至少在概念上,Python将执行三个独立的步骤来进行这个需求。这些步骤反映了Python语言中所有赋值的操作:

  1. 创建对象来代表值3。
  2. 如果变量a还不存在,则创建它。
  3. 将变量a和新对象3连接起来。

最终结果将会是类似图6-1中的Python中的一个结构。如草图所示,变量和对象存储在内存的不同部分且被链接所关联起来(链接在图中显示为一个箭头)。变量总是指向对象且从不指向其他变量,但更大的对象可能指向其他对象(比如,列表对象有它包含的对象的链接)。

image-20230225102143496

Python的这些变量到对象的链接被称为引用——也就是说,引用是一种联系,实现为内存中的指针[15]。不管变量后面何时被使用(也就是,被引用),Python自动跟随这个“变量到对象”的链接。这完全比术语暗示的要更简单。具体说来:

  • 变量是系统表中的条目,其中有指向对象链接的空间。
  • 对象是已分配内存块,有足够的空间来表示它们代表的值。
  • 引用是被自动跟随的从变量到对象的指针。

至少在概念上,每次在脚本中运行表达式产生新值时,Python会创建新对象(也就是:内存块)来表示那个值。作为优化,Python内部会缓存和重用特定种类的未修改对象,如小整数和字符串(每个0并不是真的小块内存——关于这个缓存行为后来还会详述)。但从一个逻辑的角度,它工作得好像每个表达式的结果值是一个不同的对象,而且每个对象是一个不同的内存块。

技术上讲,对象有更多的结构,而不仅仅是有足够的空间来表示它们的值。每个对象还有两个标准的头字段:类型标识符用来标记对象类型,引用计数器用来决定何时可以回收对象。要理解这两个头字段是如何被包含在模型中的,需要继续前进。


Footer 15: 有C语言背景的读者可能会觉得Python引用类似于C的指针(内存地址)。事实上,引用被实现为指针,且通常起同样的作用,特别是那些能就地修改的对象(后面会详述这一点)。然而,因为引用在被使用时,总是自动被解析,对于引用本身你事实上从不需要做任何事;这个特性消除了C语言中的许多BUG。但可以将Python引用想做C的“Void*”指针,当使用时会被自动跟随(译注:指从变量指向对象的这个过程)。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~