缺少声明语句的情况——变量,对象和引用 | 第二部分 类型与操作 —— 第 6 章: 动态类型的插曲 |《学习 python:强大的面向对象编程(第 5 版)》| python 技术论坛-大发黄金版app下载
本书到目前为止的许多例子中,当在python中运行赋值语句如 a=3
时,即使从未告诉python将名称a
作为变量使用,或a
应该代表整数对象,也可以工作。在python语言中,这些都以一种非常自然的方式发展,如下:
变量创建
变量(也就是:名称),如a
,当代码首次给其赋值时被创建。未来的赋值会改变已创建名称的值。技术上讲,python在代码运行前检测到一些名称,但可以将其想为初始赋值创建了变量。
变量类型
变量从没有任何类型信息或与其有关的限制。类型概念和对象联系在一起,而非名称。变量本质上是通用的,它们总是简单地在某个特殊的时间点引用某个特殊对象。
变量使用
当变量出现在表达式中时,它立即被其当前引用的对象替换掉,不管该对象可能是什么。而且,所有对象在能被使用前必须被明确地赋值;引用未赋值变量会导致错误。
总的来说,变量在赋值时被创建,能引用任何类型的对象,且在被引用前必须被赋值。这意味着从不需要声明脚本使用的名称,但必须在能更新它们前先初始化:比如,在能给计数器增加计数前,必须将其初始化为0。
这种动态类型模型和传统语言的类型模型差异很大。当开始学习这个模型时,如果明白名称和对象之间的差异就会更容易理解。比如,当如下为变量赋值时:
>>> a = 3 # 为对象分配名称
至少在概念上,python将执行三个独立的步骤来进行这个需求。这些步骤反映了python语言中所有赋值的操作:
- 创建对象来代表值3。
- 如果变量
a
还不存在,则创建它。 - 将变量
a
和新对象3
连接起来。
最终结果将会是类似图6-1中的python中的一个结构。如草图所示,变量和对象存储在内存的不同部分且被链接所关联起来(链接在图中显示为一个箭头)。变量总是指向对象且从不指向其他变量,但更大的对象可能指向其他对象(比如,列表对象有它包含的对象的链接)。
python的这些变量到对象的链接被称为引用——也就是说,引用是一种联系,实现为内存中的指针[15]。不管变量后面何时被使用(也就是,被引用),python自动跟随这个“变量到对象”的链接。这完全比术语暗示的要更简单。具体说来:
- 变量是系统表中的条目,其中有指向对象链接的空间。
- 对象是已分配内存块,有足够的空间来表示它们代表的值。
- 引用是被自动跟随的从变量到对象的指针。
至少在概念上,每次在脚本中运行表达式产生新值时,python会创建新对象(也就是:内存块)来表示那个值。作为优化,python内部会缓存和重用特定种类的未修改对象,如小整数和字符串(每个0并不是真的小块内存——关于这个缓存行为后来还会详述)。但从一个逻辑的角度,它工作得好像每个表达式的结果值是一个不同的对象,而且每个对象是一个不同的内存块。
技术上讲,对象有更多的结构,而不仅仅是有足够的空间来表示它们的值。每个对象还有两个标准的头字段:类型标识符用来标记对象类型,引用计数器用来决定何时可以回收对象。要理解这两个头字段是如何被包含在模型中的,需要继续前进。
footer 15: 有c语言背景的读者可能会觉得python引用类似于c的指针(内存地址)。事实上,引用被实现为指针,且通常起同样的作用,特别是那些能就地修改的对象(后面会详述这一点)。然而,因为引用在被使用时,总是自动被解析,对于引用本身你事实上从不需要做任何事;这个特性消除了c语言中的许多bug。但可以将python引用想做c的“void*”指针,当使用时会被自动跟随(译注:指从变量指向对象的这个过程)。