- 译者序
- 前言
- 第1章 问答环节
- 第2章 Python 如何运行程序
- 第3章 如何运行程序
- 第4章 介绍 Python 对象类型
- 第5章 数字
- 第6章 动态类型简介
- 第7章 字符串
- 第8章 列表与字典
- 第9章 元组、文件及其他
- 第10章 Python 语句简介
- 第11章 赋值、表达式和打印
- 第12章 if 测试和语法规则
- 第13章 while 和 for 循环
- 第14章 迭代器和解析,第一部分
- 第15章 文档
- 第16章 函数基础
- 第17章 作用域
- 第18章 参数
- 第19章 函数的高级话题
- 第20章 迭代和解析,第二部分
- 第21章 模块:宏伟蓝图
- 第22章 模块代码编写基础
- 第23章 模块包
- 第24章 高级模块话题
- 第25章 OOP:宏伟蓝图
- 第27章 更多实例
- 第28章 类代码编写细节
- 第29章 运算符重载
- 第30章 类的设计
- 第31章 类的高级主题
- 第32章 异常基础
- 第34章 异常对象
- 第35章 异常的设计
- 第36章 Unicode 和字节字符串
- 字符串基础知识
- Python 的字符串类型
- 文本和二进制文件
- Python 3.0 中的字符串应用
- 转换
- 编码 Unicode 字符串
- 编码非ASCII文本
- 编码和解码非ASCII文本
- 其他 Unicode 编码技术
- 转换编码
- 在 Python 2.6 中编码 Unicode 字符串
- 源文件字符集编码声明
- 使用 Python 3.0 Bytes 对象
- 序列操作
- 创建 bytes 对象的其他方式
- 混合字符串类型
- 使用 Python 3.0(和 Python 2.6)bytearray 对象
- 使用文本文件和二进制文件
- Python 3.0 中的文本和二进制模式
- 类型和内容错误匹配
- 使用 Unicode 文件
- 在 Python 3.0 中处理 BOM
- Python 2.6 中的 Unicode 文件
- Python 3.0 中其他字符串工具的变化
- Struct二进制数据模块
- pickle对象序列化模块
- XML解析工具
- 本章小结
- 本章习题
- 习题解答
- 第37章 管理属性
- 第38章 装饰器
- 第39章 元类
- 附录A 安装和配置
- 附录B 各部分练习题的解答
- 作者介绍
- 封面介绍
第6章 动态类型简介
正像本书稍后介绍的那样,在Python中,我们并不会声明脚本中使用的对象的确切类型。事实上,程序甚至可以不在意特定的类型;相反地,它们能够自然地适用于更广泛的场景下。因为动态类型是Python语言灵活性的根源,让我们先简要地看一下这个模块。
缺少类型声明语句的情况
如果你有学习静态编译类型语言C、C++或Java的背景,学到这里,你也许会有些困惑。到现在为止,我们使用变量时,都没有声明变量的存在和类型,但变量还可以工作。例如,在交互会话模式或是程序文件中,当输入a=3时,Python怎么知道那代表了一个整数呢?在这种情况下,Python怎么知道a是什么?
一旦你开始问这样的问题,就已经进入了Python动态类型模型的领域。在Python中,类型是在运行过程中自动决定的,而不是通过代码声明。这意味着没有必要事先声明变量(只要记住,这个概念实质上对变量、对象和它们之间的关系都适用,那么这个概念也就很容易理解并掌握了)。
变量、对象和引用
就像本书已使用过的很多例子一样,当在Python中运行赋值语句a=3时,即使没有告诉Python将a作为一个变量来使用,或者没有告诉它a应该作为一个整数类型对象,但一样也能工作。在Python语言中,这些都会以一种非常自然的方式完成,就像下边这样:
变量创建
一个变量(也就是变量名),就像a,当代码第一次给它赋值时就创建了它。之后的赋值将会改变已创建的变量名的值。从技术上来讲,Python在代码运行之前先检测变量名,可以当成是最初的赋值创建变量。
变量类型
变量永远不会有任何的和它关联的类型信息或约束。类型的概念是存在于对象中而不是变量名中。变量原本是通用的,它只是在一个特定的时间点,简单地引用了一个特定的对象而已。
变量使用
当变量出现在表达式中时,它会马上被当前引用的对象所代替,无论这个对象是什么类型。此外,所有的变量必须在其使用前明确地赋值,使用未赋值的变量会产生错误。
总而言之,变量在赋值的时候才创建,它可以引用任何类型的对象,并且必须在引用之前赋值。这意味着,不需要通过脚本声明所要使用的名字,但是,必须初始化名字然后才能更新它们;例如,必须把计数器初始化为0,然后才能增加它。
这种动态类型与传统语言的类型相比有明显的不同。刚入门时,如果清楚地将变量名和对象划分开来,动态类型是很容易理解的。例如,当我们这样说时:
至少从概念上来说,Python将会执行三个不同的步骤去完成这个请求。这些步骤反映了Python语言中所有赋值的操作:
1.创建一个对象来代表值3。
2.创建一个变量a,如果它还没有创建的话。
3.将变量与新的对象3相连接。
实际的效果是如图6-1所示的一个在Python中的内部结构。如图6-1所示,变量和对象保存在内存中的不同部分,并通过连接相关联(这个连接在图6-1中显示为一个箭头)。变量总是连接到对象,并且绝不会连接到其他变量上,但是更大的对象可能连接到其他的对象(例如,一个列表对象能够连接到它所包含的对象)。
图 6-1 变量名和对象,在运行a=3后。变量a变成对象3的一个引用。在内部,变量事实上是到对象内存空间(通过运行常量表达式3而创建)的一个指针
在Python中从变量到对象的连接称作引用。也就是说,引用是一种关系,以内存中的指针的形式实现[1]。一旦变量被使用(也就是说被引用),Python自动跟随这个变量到对象的连接。这实际上比术语所描述的要简单得多。以具体的术语来讲:
·变量是一个系统表的元素,拥有指向对象的连接的空间。
·对象是分配的一块内存,有足够的空间去表示它们所代表的值。
·引用是自动形成的从变量到对象的指针。
至少从概念上讲,在脚本中,每一次通过运行一个表达式生成一个新的值,Python都创建了一个新的对象(换言之,一块内存)去表示这个值。从内部来看,作为一种优化,Python缓存了不变的对象并对其进行复用,例如,小的整数和字符串(每一个0都不是一块真正的、新的内存块,稍后会介绍这种缓存行为)。但是,从逻辑的角度看,这工作起来就像每一个表达式结果的值都是一个不同的对象,而每一个对象都是不同的内存。
从技术上来讲,对象有更复杂的结构而不仅仅是有足够的空间表示它的值那么简单。每一个对象都有两个标准的头部信息:一个类型标志符去标识这个对象的类型,以及一个引用的计数器,用来决定是不是可以回收这个对象。要理解这两个头部信息对模型的影响力,我们需要继续学习下去。
[1]有C语言背景的读者可能会发现,Python的引用类似于C的指针(内存地址)。事实上,引用是以指针的形式实现的,通常也扮演着相同的角色,尤其是那些在原处修改的对象(我们将在稍后部分进行讨论)。然而由于在使用引用时会自动解除引用,你没有办法拿引用来做些什么:这种功能避免了许多C可能出现的Bug。你可以把Python的引用想成C的void指针,每当使用时就会自动运行下去。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论