Python 类型层次结构 从其他语言过渡到 Python 编程语言时需要学习的最重要的课程之一是,Python 中的每样东西都是对象。这一点可能并没有什么特别之处,尤其是对于熟悉面向对象的语言(如 C++、Java 或 C#)的人来说。然而,Python 的面向对象原理与其他语言不同,主要表现在两个方面:第一,Python 中的所有数据值都被封装在相关对象类中。第二,Python 程序中的所有东西都是可以从程序访问的对象,即使是您编写的代码也不例外。 大多数流行的编程语言都有多个内置的数据类型,在这一方面 Python 也一样。例如,C 编程语言具有整型和浮点类型。由于谱系相同,Java 语言和 C# 具有内置类型也不足为奇。这意味着在 C 程序中,可以编写 int i = 100 来创建和初始化整型变量。在 Java 和 C# 中,此方法也是可能的,而且使用它们的自动装箱功能,在需要时这两种语言还可以把这种简单的内置类型转换为 Integer 对象。 另一方面,Python 不包含像 int 这样的简单类型 —— 只有对象类型。如果 Python 中需要整数值,将整数赋值给相应变量(如 i = 100 )即可。在后台,Python 将创建一个整数对象,并将对新对象的引用赋值给变量。问题的关键是:Python 是一种动态类型化语言,所以无需声明变量类型。事实上在单个程序中,变量的类型是可以改变(多次)的。 一种直观演示动态类型化工作方式的简单方法是,设想单个名为 PyObject 的基类,让 Python 中的所有其他对象类型都继承它。在这一模型中,您创建的所有变量都将引用在总的类层次结构中创建的对象。如果您还让 PyObject 类记录曾创建并分配给变量的子类的实际类型或名称,则 Python 程序可正确确定程序执行过程中需要采取的步骤。 上一段描述 Python 的面向对象的模型图像是对 Python 的实际工作方式很好的模拟。除此之外,Python 还可以使用类型函数来简化对变量类型的确定。(本例还介绍如何使用带有 # 字符的内联注释。) 清单 2. 演示 Python 简单类型 可以将 PyObject 类之下的所有 Python 类划分为 Python 运行时解释器可以使用的四个主要类别: * 简单类型 —— 基本构建块,如 int 和 float。 * 容器类型 —— 保存其他对象。 * 代码类型 —— 封装 Python 程序的元素。 * 内部类型 —— 程序执行期间使用的类型。 到本系列结束时,我会把所有不同类别都介绍给大家。但是在这第一篇文章中,我重点介绍简单类型。 简单类型 Python 有五个内置的简单类型:bool、int、long、float 和 complex。这些类型是不可变的,就是说整数对象一旦创建,其值便不可更改。相反,系统将创建新的简单类型对象并将其赋值给变量。通过 Python id 函数,可以查看基本 PyObject 标识的变更方式: 清单 3. 使用 Python id 函数 此方法看似容易丢失对象,会导致内存泄漏。但是,Python 像 C# 和 Java 一样,使用了垃圾回收功能,以释放用于保存不再引用的对象的内存,如上例中用于保存 100 的整数对象。 布尔类型 Python 中最简单的内置类型是 bool 类型,该类型包括的对象仅可能为 True 或 False: 清单 4. bool 类型 因为只有两个可能值,所以布尔类型是惟一的。Python 解释器提供这仅有的(也是必需的)两个 bool 对象:True 和 False。在任何时候,在 Python 程序需要这些对象时,变量只能相应地引用其中一个值。清单 5 显示 bb 变量如何具有同一个 id,不管您直接赋予它 b 变量的值还是直接赋予它 True 对象。 清单 5. bb 变量的值 布尔对象名称的大小写是至关重要的,因为 true(和 false)是未定义的: 清单 6. 未定义的 true 和 false 在这一点上,bool 类型可能看起来不是很有用。不过顾名思义,布尔表达式是依赖于名称的,如下所示: 清单 7. 布尔表达式 很多程序利用布尔表达式,Python 提供一整套布尔比较和逻辑运算,详细信息请分别参见表 1 和表 2。 表 1. Python 中的布尔比较运算符 表 2. Python 中的逻辑运算符 在 Python 中,关于 or 和 and 逻辑运算符有意思的是,它们都是快捷运算符。简言之,如果给定表达式 x or y,则仅当 x 为 False 时才会计算 y。同样地,如果给定表达式 x and y,则仅当 x 为 True 时,才会计算 y。此功能可以增强表达式求值的性能(尤其是针对长的或复杂的表达式),然而对于习惯于从其他语言学来的不同规则的程序员而言,则容易犯错。 数值类型 Python 中其他四个简单的内置类型都是数值类型:int、long、float 和 complex。在程序中,数值类型很常见,不管使用的是什么语言。Python 对算术运算提供完整支持,包括加法、减法、乘法和除法(参见表 3)。 表 3. Python 中的算术运算 乘法和除法运算符(表 3 中列出的前四个)具有高于加法和减法的优先级。如前所述,您可以通过使用括号分组子表达式,将其分离出来以提高优先级。 Python 与 Java 语言不同,Java 语言通常定义允许的数值类型的范围,而 Python 在这一点上更像 C,因为它的类型范围是依赖于平台的。您可以使用 int 和 long 两种类型来保存整数值,它们的不同点在于 int 是一种 32 位的整数值。因而,它被限制为只能保存从 -232 到 232 - 1 之间的值(在多数平台上)。与此相反,长整数类型的精度不受限,仅计算机内存对它有影响。要通知 Python 应该按照长类型处理整数,只需将 L 附加到数字的末尾,如 100L。在 Python 中,浮点值始终是按双精度处理的;因此 Python 的 float 类型对应于 C 类语言中的双精度。 与数值类型相关的其他两个重点是常量(如上例中的 100,只是明确表达的数字)和位运算。程序员一般在十进制系统(以 10 为基数)中工作。但是,有时其他系统也相当有用,尤其是我们知道计算机是基于二进制的。Python 可以提供对八进制(以 8 为基数)和十六进制(以 16 为基数)数字的支持。要通知 Python 应该按八进制数字常量处理数字,只需将零附加在前面。将一个零加上一个 x 附加在数字的前面是告诉 Python 按十六进制数值常量处理数字,如以下代码所示: 清单 8. 通知 Python 按十六进制数值常量处理数字 当您具有容易的方式来表达数值常量时,尤其是十六进制,就可以容易地构建对应于特定测试用例的标志,这是一种常见的编程技术。例如,一个 32 位的整数可以存储 32 个标志值。使用位测试,可以容易地测试标志变量上的特定标志。Python 中位运算的完整列表如表 4 所示。 表 4. Python 中的位运算 清单 9. Python 将所有操作数转换为最复杂的操作数 尽管 Python 会与您预期的一样转换操作数,但是语言并不基于运算符转换操作数,如 1/3 示例中所示,其计算结果为整数。如果要强制取得浮点结果,则必须确保操作数中至少有一个为浮点类型。 complex 类型 最后一种类型 complex 可能是大多数程序员难以识别的,因为它不是其他编程语言中常见的内置数据类型。而对于工程师和科学家来说,复数却是个司空见惯的概念。从形式上讲,复数 具有实部和虚部两个部分,都由 Python 中的 float 类型来表示。虚数 是 -1 的平方根的倍数,用 i 或 j 表示 —— 取决于您被培养为科学家还是工程师。在 Python 中,复数的虚部被表示为 j: 清单 10. 复数的虚部 本例是一个实部为 3.0 和虚部为 1.2 的复数。注意,通过使用复杂对象的 real 和 imag 属性,即可访问复数的不同部分。 它们真是对象吗? 到此为止,我已经介绍了 Python 只处理对象类型,然而示例中好像并没有什么对象。最后还有一个问题,构造函数在哪里?对于简单的内置数据类型,Python 替您做了大量的工作。不过,构造函数还在那里(其名称与相关数据类型的名称相同),如果您愿意,可以直接使用它们,如下所示: 清单 11. Python 构造函数 |
您可以看到,我使用的是运行于 Apple OS X 系统上的 Python V2.4。但是,不管操作系统是什么,基本原理都是一样的,而且在本例中,所用的是 Python 的哪一个实际版本也无所谓。我虽然不了解您,但是此 Hello World! 练习比我学过的 C、C++ 甚至 Java™ 语言的对应练习容易多了。这种简单性就是使用 Python 解释器的主要优点之一。开发人员可以快速试验一个想法、研究一种对象属性或不同算法,而无需编译、执行和测试任何代码。
第 2 部分: 探索 Python 类型的层次结构 —— 了解对象和容器
Python 编程语言是一种简单但功能强大的语言。本文将探索该语言的对象属性,开头部分介绍了一些简单的内置数据类型。此外,本文还介绍了 Python 元组类,并用它演示容器类型的概念。
在 Python 语言中,所有事物都是程序可以访问的对象, 其中包括保存整数的简单类型,以及您编写的实际代码和这些代码在 Python 解释器中的表示。对于熟悉其他编程语言的人来说,此行为可能导致某些混乱。但是,在实践中,不会出现这种情况。Python 有一个良好定义的类型(或对象)层次结构。该层次结构在概念上可以划分为四种类别:简单类型、容器类型、代码类型 和内部类型。
简单类型
内置到 Python 编程语言中的简单数据类型包括:
* bool
* int
* float
* complex
支持简单数据类型不是 Python 独有的功能,因为多数现代编程语言都具有完整类型补充。例如 Java™ 语言甚至有一组更丰富的原始数据类型:
* byte
* short
* int
* long
* float
* double
* char
* boolean
但是,在 Python 中,简单数据类型并不是原始数据类型,而是完善的对象,它们有自已的方法和类。另外,这些简单的内置类型是不可改变的,这意味着:创建对象之后,您无法更改对象的值。如果需要新值,则必须创建新的对象。Python 简单数据类型的不可改变特性与其他多数流行语言(如 Java 语言)处理简单原始类型的方式不同。但是,当您对这些简单数据类型的对象属性有了更多的了解之后,就很容易理解这种差异。
所以,整数如何能够拥有一些方法?它仅仅是一个数字吗?不是的,至少在 Python 中答案是否定的。您自已可以对它进行检验:仅借助内置的 help 方法,就可以向 Python 解释器咨询关于 int 对象的信息(参见清单 1 )。
清单 1. Python 解释器: 用于整数对象的 Help
这具体说明了什么?只有一个事情,那就是可以方便地从 Python 解释器中得到帮助,但是从后面部分可以获得更多帮助。第一行告诉您正在查看 int 类的帮助页面,它是一个内置的数据类型。如果您对面向对象的编程的概念不太熟悉,那么可以将类 想像成只是一个用于构建特殊事物并与之交互的蓝图。好比房子的设计蓝图,不仅显示如何构建房子,还显示房子完工之后,如何更好地使用房子。例如,设计图会显示不同房间的位置、在房间之间的移动方式以及出入房子的通道情况。
第一行的下面是对实际 int 类的详细说明。在这一点上,您可能不熟悉如何在 Python 中创建类,因为显示的语法类似于外语。没关系,我将在另一篇文章中对此进行全面介绍。现在,您只需要知道:int 对象是从 object 类中继承而来,它是 Python 中许多内容的一个基类。
后面的几行介绍 int 类的构造函数。构造函数 只是创建特定类实例(或对象) 的特殊方法。构造函数方法好比建筑承包人,它利用房子的设计图建房子。在 Python 中,构造函数的名称与其创建的类的名称相同。类可以有不同的构造函数方法,这些方法是通过类名称后的圆括号内附带的不同属性进行区分。类可以有不同构造函数方法的较好的一个例子就是 int 类, 实际上,您可以用多种方法调用它,具体采用哪种方法取决于圆括号中放置的参数(参见清单 2)。
清单 2. Python 解释器:int 类构造函数 这四个构造函数调用创建了四个不同的整数。第一个构造函数创建了一个整数对象,其值为 0,在没有值提供给 int 类构造函数的情况下,该值是所使用的默认值。第二个构造函数根据规定创建了一个值为 100 的整数。第三个构造函数采用了字符串“100”并创建了以 10 为基数的整数值(常见的十进制系统)。最后一个构造函数也采用了字符串“100”—— 但是它使用基数 8 来创建整数值,通常称为 八进制。不过,该值在输出时会被转换成十进制数值,这就是该数字显示为 64 的原因。
您可能想知道如果省略了构造函数调用中的圆括号将会发生什么。在这种情况下,您可以向该变量分配一个实际的类名称,有效地为原先的类创建一个别名(参见清单 3)。
清单 3. Python 解释器:int 类型 真是太棒了!您立即可以创建一个由内置 int 类定义的新数据类型。但请注意不好的一面,不要滥用这一新功能。优秀的程序员除了使代码具有良好性能外,还应努力使代码清淅。这类编码技巧的确有其使用价值,但它们并不常见。
使用 Python 解释器可以使新的 Python 程序员简化学习过程,少走弯路。如果您想详细了解 Python 内的 help 工具,只需在 Python 解释器中的命令提示符下键入 help() ,就可以访问交互式的帮助工具(参见清单 4)。
清单 4. Python 解释器:帮助解释器 您可能已经对此有所了解,但在 help> 提示符处输入 int 可以显示那些为以前的 int 类显示的类描述。
容器类型
到目前为止,已经谈论了许多 Python 语言中使用的简单类型。但是多数程序并不简单,它们涉及通常由简单类型组成的复杂数据。因此,现在的问题就成了“如何在 Python 中处理复杂数据?”
如果您熟悉面向对象的语言,如 Java 或 C#,那么您可能认为该问题的答案很简单:只需创建一个新类来处理复杂的数据即可。该方法也适用于 Python,原因是 Python 支持通过类创建新类型。但是,在多数情况下,Python 还可以提供更为简单的方法。当您的程序需要一次处理多个对象时,就可以利用 Python 容器类:
* tuple
* string
* unicode
* list
* set
* frozenset
* dictionary
这些容器类型提供了两种功能。前六个类型是有序的,最后一个类型 dictionary 则是一个映射。有序类型与映射类型的区别较为简单。有序类型 仅仅是指对象的顺序。所有的有序类型(除 set 和 frozenset 类型外)都支持访问给定顺序的对象。相比之下,映射容器 则用于保存那些对顺序不是很敏感的对象;通过提供可以找到关系值的密钥,就可以从容器中提取值。
容器类型间的另一个不同点来自于它们所持有的数据的特性,下面四种容器类型的顺序是不可变的:
* tuple
* string
* unicode
* frozenset
这意味着在您创建了这些容器类型之一后,所存储的数据就不可更改。如果出于某种原因需要更改数据,则需要创建一个新容器来保存新的数据。
后三种容器类型(list、set 和 dictionary)都是可变容器,因此,它们可以根据需要更改保存的任何数据(但在 dictionary 中所使用的密钥是不可变的,就像您房间的钥匙)。虽然可变容器非常灵活,但它们的动态特性会对性能造成影响。例如,tuple 类型,尽管它是不可变的,灵活性较差,但在同一环境中使用时,它们通常比 list 类型快得多。
这些容器类提供了强大的功能,它们通常是多数 Python 程序的核心。本文的其余部分讨论了 tuple 类型,它用于引入许多与创建和使用 Python 中的容器类型有关的基本概念。其余的类型将在以后的文章中讨论。
元组
tuple 类型像一个口袋,在出门前可以把所需的任何东西一股脑地放在里面。您可以将钥匙、驾驶证、便笺簿和钢笔放在口袋里,您的口袋是存放各种东西的收集箱。Python 的 tuple 类型与口袋类似,它可以存放不同类型的对象。您只需向变量分配一个用逗号分隔的对象序列,就可以创建一个 tuple(参见清单 5)。
清单 5. Python 解释器:创建一个 tuple 该示例代码显示了如何以多种方式创建 tuple。第一种方法是创建一个包含从 0 到 9 整数序列的 tuple。第二种方法与第一种相同,但这次省去了括号。在创建一个 tuple 时,括号通常是可选的,但有时是必需的,这取决于上下文。结果,您会习惯性地使用括号来减少混淆。最后一个 tuple tc 使用了一个实际的类构造函数来创建 tuple。这里重要的一点是,构造函数构成中仅有一个变量,因此您必须在括号中包括对象序列。最后两个构造函数调用演示了如何通过在括号内不放任何东西来创建空的 tuple (et),以及如何通过将一个逗号放在序列中仅有的一个项目后面来创建 tuple (st)。
使用口袋装东西的一个主要原因是为了方便生活。但要求在需要这些东西的时候能够迅速地从口袋中取出它们。Python 中的多数容器类型(其中包括 tuple)允许您使用方括号操作符从集合中方便地访问数据项。但 Python 比其他语言更具灵活性:您可以使用通常称为分段 的方法选择一个项目或多个有序项目(参见清单 6)。
清单 6. Python 解释器:从 tuple 访问项目 在创建简单的 tuple 之后,前面的示例显示如何选择一个数据项 —— 在本示例中是整数 2。这时,请注意 Python 使用了零排序,其中集合中的项目从零开始编号。如果您熟悉使用 Java 语言、C# 或其他从 C 语言派生的语言进行编程,那么您应该非常熟悉此行为。否则,该概念也是非常简单的。用于访问数据项的索引只声明集合中越过第一个数据项有多远,或者称为序列,您需要去获得所需的内容。因此,要获得第三个数据项(在本示例中为整数 2),您需要从第一个数据项起越过两个数据项。在访问第三个数据项时,Python 知道它是一个整数对象。您还可以方便地从集合中提取多个数据项。在本示例中,您创建了一个新的 tuple,其值为从最初的 tuple 开始第一、第二和第十个值。
其余的示例显示了如何使用 Python 的分段功能从序列中一次选择多个数据项。术语分段 是指从序列中对数据项进行分段的方法。分段的工作方式是声明开始索引、结束索引和一个可选的步骤大小,全部都用分号分隔。因此,t[2:7] 将 tuple 中的第三到第七个数据项分段,而 t[2:7:2] 则对每两个数据项进行分段,从 tuple 中的第三个数据项开始一直到第七个数据项。
我目前创建的 tuple 对象是同类的,它们仅包含整数对象。所幸的是,tuple 要比显示的示例复杂得多,因为 tuple 实际上是一个异构容器(参见清单 7)。
清单 7. Python 解释器:异构的 tuple 您会看到,创建可以拥有各种类型数据项(其中包括另一 tuple)的 tuple 是多么方便。并且可以使用方括号操作符以相同的方式访问所有数据项,它支持将不同类型的有序数据项分段。然而,tuple 是不可变的。因此,当我尝试更改第五个元素时,发现不允许对数据项分配。打一个简单的比方,在您将某些东西放入口袋后,改变所取东西的惟一方式是取一个新口袋,并将所有数据项放进去。
如果需要在现有 tuple 中创建一个包含数据项子集的新 tuple,最简单的方法是使用相关的片段,并根据需要同时添加子集(参见清单 8)。
清单 8. Python 解释器:使用 tuple 您还可以将现有 tuple 的片段与新 tuple 的片段合并在一起。使用片段语法,无需指定开始或结束索引,就可以制作现有 tuple 的副本。最后两个示例也非常有趣。内置的 len 方法告诉您 tuple 中数据项的数量。从嵌套的 tuple 访问数据项也非常简单:选择嵌套的 tuple,然后从中访问有趣的数据项。
您还可以从称为打包 的过程的一组现有变量中创建一个tuple。反之亦然,其中,tuple 中的值被指派给变量。这之后的过程称为解包,它是用于许多情形的功能十分强大的技术,其中包括希望从一个函数中返回多个值。在解包 tuple 时,仅有的问题是必须为 tuple 中的每个数据项提供一个变量(参见清单 9)。
清单 9. Python 解释器:打包和解包 tuple 简化概念
尽管看上去十分复杂,但 Python 的对象属性实际上简化了 Python 语言新手常常面临的一些更为复杂的概念。在了解如何使用对象之后,所有东西都是对象这一概念意味着您已经进一步理解了一些新概念。如 Python 的容器类型。使困难的任务变得简单化是使用 Python 得到的常见好处之一;另一个例子是内置的帮助工具,只需在 Python 提示符处输入 help(),就可以在 Python 解释器中看到该工具。由于生活不是用一些简单的概念描述的,所以 Python 提供了一组丰富的容器(即集合)对象。在本文中,我介绍了其中的最简单的对象 —— tuple。要正确使用 tuple,就需要熟悉它的工作方式。但是,由于许多其他容器类型具有类似的功能,其中包括分段以及打包或解包,了解 tuple 的工作原理意味着您已经开始完全理解 Python 中的其他容器类型。
第 3 部分: 探索 Python 类型的层次结构 —— 使用字符串
字符串
在 Python 中创建字符串对象非常容易。只要将所需的文本放入一对引号中,就完成了一个新字符串的创建(参见清单 1)。如果稍加思考的话,您可能会感到有些困惑。毕竟,有两类可以使用的引号:单引号 (') 和双引号 (")。幸运的是,Python 再一次使这种问题迎刃而解。您可以使用任意一类引号来表示 Python 中的字符串,只要引号一致就行。如果字符串是以单引号开始,那么必须以单引号结束,反之亦然。如果不遵循这一规则,则会出现 SyntaxError 异常。
清单 1. 在 Python 中创建字符串
第二,如果字符串用一行表示太长,您可以使用 Python 连续字符:反斜线 (\) 来对字符串进行折行。从内部机制看,在创建字符串时换行符会被忽略,在打印字符串时可以看出这一点。您可以结合使用这两个功能,来创建包含较长段落的字符串,如清单 2 所示。
清单 2. 创建长字符串 编者注:上面的示例已折行处理,这样使页面布局更合理。事实上,它本来显示为一个较长的行。
注意,当打印 passage 字符串时,所有格式将被删除,只保留一个非常 长的字符串。通常,您可以使用控制符来表示字符串中的简单格式。例如,要表示一个新行开始,您可以使用换行控制符 (\n);要表示插入一个制表符(预设空格数),可以使用制表符控制符 (\t),如清单 3 所示。
清单 3. 在字符串中使用控制符 清单 3 中的第一段按照您预期的方式使用了控制符。该段已具备良好的格式,阅读非常方便。第二个示例虽然也进行了格式化处理,但它引用的是所谓的原始字符串,即没有应用控制符的字符串。您始终可以认出原始字符串,因为该字符串的起始引号的前面有一个 r 字符,它是 raw 的缩写。
我不了解您讲的有什么可取之处,虽然这种方法可行,但创建一个段落字符串似乎非常因难。当然一定有更好的方法。与往常一样,Python 提供了一种非常简单的方法用于创建长字符串,该方法可保留创建字符串时所使用的格式。这种方法是使用三个双引号(或三个单引号)来开始和结束长字符串。在该字符串中,您可以使用任意多的单引号和双引号(参见清单 4)。
清单 4. 使用三个引号的字符串 将字符串作为一个对象
如果阅读了本系列前两篇文章中的任何一篇文章,那么在您的脑海中会立即浮现出这样一句话:在 Python 中,所有事物都是对象。到目前为止,我还没有涉及到关于 Python 中的字符串的对象特性的问题,但是,与往常一样,Python 中的字符串就是对象。事实上,字符串对象是 str 类的一个实例。正如您在 探索 Python,第 2 部分 中看到的,Python 解释器包括一个内置帮助工具(如清单 5 所示),它可以提供关于 str 类的信息。
清单 5. 获取关于字符串的帮助信息 使用单引号、双引号和三引号语法创建的字符串仍然是字符串对象。但是您也可以使用 str 类构造函数显式地创建字符串对象,如清单 6 所示。该构造函数可以接受简单的内置数值类型或字符数据作为参数。两种方法都可以将输入的内容更改为新的字符串对象。
清单 6. 创建字符串 清单 6 中的例子也展示了关于 Python 字符串的几个其他重要方面。第一,通过将其他字符串添加在一起,可以创建新的字符串,具体方法可以使用 + 运算符,或者干脆使用适当的引号将字符串连在一起。第二,如果需要重复短字符串来创建长字符串,可以使用 * 运算符,将字符串重复一定的次数。我在本文开头说过,在 Python 中,字符串是不变的字符序列, 上例中的最后几行说明了这一点,我首先创建一个字符串,然后通过添加其他字符串对它进行修改。从对 id 方法两次调用的输出中可以看出,创建的新字符串对象中保存的是向原字符串中添加文本的结果。
str 类包含大量的用于操作字符串的有用方法。这里不做一一介绍,您可以使用帮助解释器获得有关信息。现在让我们了解一下四个有用的函数,并演示其他 str 类方法的工具。清单 7 演示了 upper、lower、split 和 join 方法。
清单 7. 字符串方法 前两个方法 upper 和 lower 很容易理解。它们只是分别将字符串都转换成大写字母或小写字母。split 方法很有用,因为它可以将一个字符串分成几个较小的字符串序列,方法是将令牌字符(或给定字符序列中的任何字符)用作断开位置的指示器。所以,第一个 split 方法示例使用默认的令牌将字符串“This is a test”拆分开,此令牌可以是任何空白字符(这个序列包括空格、制表符和换行符)。第二个 split 方法演示如何使用不同的令牌字符(本例中使用的是冒号)将一个字符串分成一系列字符串。最后的一个例子显示如何使用 join 方法,该方法的作用与 split 方法相反, 可以使多个短字符串序列形成一个长字符串。在本例中,使用冒号将 tuple 包含的由单个字符构成的字符串序列连接在一起。
将字符串用作字符的容器
在本文的开头部分,我着重强调了 Python 中的字符串是不变的字符序列。本系列的第 2 部分 探索 Python,第 2 部分 介绍了 tuple,它也是一个不变的序列。tuple 通过以下方式支持访问序列中的元素:使用索引符号,使用片段分离序列中的元素,以及使用特定的片段或将不同的片段添加在一起来创建新的元组。根据这一情况,您可能想知道是否可以将同一技巧应用于 Python 字符串。如清单 8 所示,答案显然是“可以”。
清单 8. 字符串方法 在 Python 中,将字符串作为字符序列进行处理是非常简单的。您可以获得单个元素,将不同的元素添加在一起,切出几个元素,甚至将不同的片段添加在一起。进行切片的一个非常有用的特性是,在开始之前或结束之后进行较多切片不会抛出异常,只是相应地以默认方式开始或结束该序列。相反,如果您试图使用允许范围之外的索引来访问单个元素,则会得到一个异常。这种行为说明了为什么 len 方法是如此重要。
字符串:功能强大的工具
在本文中,我介绍了 Python 字符串,它是一种不变的字符序列。在 Python 中,您可以使用多个方法很容易地创建字符串,其中包括使用单引号、双引号或更灵活的方式,即使用一组三个引号。假设 Python 中的每个事物都是一个对象,您可以使用底层的 str 类方法来获得附加功能或直接使用字符串的序列功能。
第 4 部分: 探索 Python 类型的层次结构 —— 使用列表 Python 提供了一系列有用的功能,其中 list 类是最重要的功能之一。本文介绍 list 类,并演示了众多方法中的一些方法,了解如何使用这些方法简化困难的编程任务。 Python list 在介绍 Python tuple 时,我使用了类比的方法,将其比做一个袋子,您可以在袋子中存放不同的东西。Python list 与此非常类似,因此,它的功能与袋子的功能也非常类似。但有一点是不同的,即您可以使用方括号创建 list,如清单 1 所示。 清单 1. 在 Python 中创建一个 list 本例展示如何创建包含从 0 到 9(包括 0 和 9)的简单 list,以及如何创建一个空列表和一个包含单个条目的列表。如果您还记得的话,创建单个条目的 tuple 还需要在单个条目后面跟一个逗号。这是区分单个条目 tuple 与方法调用的必要条件,这一点将在以后的文章中详细讨论。而对于 list,则是不必要的,尽管也允许使用单个逗号。 与往常一样,要获取有关 Python 主题的更多信息,您可以使用内置的帮助解释器,例如,清单 2 展示了如何开始 list 类的帮助描述。 清单 2. 获取有关 list 的帮助 如果仔细观察清单 2 中对 list 类的描述,您会看到其中提供了两个不同的构造函数:一个没有参数,另一个接受一个序列类作为参数。因此,使用构造函数及方括号简化符号,可以创建 list。这就提供了很大的灵活性,原因是您可以方便地将现有的序列,如 tuple 或 string 转换为 list,如清单 3 所示。不过,请注意,传递的参数必须是序列 —— 并且不只是对象序列 —— 否则将会出现错误。对于任何序列类型,您都可以使用 len 方法容易地查找序列中条目的数量。 清单 3. 直接创建 list 对象 正如您看到的,创建 list 是很容易的,如果还没有尝试过,现在可以试一试。您不仅能够将序列直接传递给构造函数,还可以将拥有元组或字符串的变量传递给 list 构造函数。 很明显,序列较为有用的主要原因是它可以非常方便地访问序列中的条目。如果还记得对 tuple 的讨论,便知道可以在序列中一次访问一个条目或者通过将条目切片来访问条目。Python list 也可以使用相同的技术,如清单 4 所示。 清单 4. 从 list 访问条目 在以前的文章中已经了解到,切片 是一个非常有用的概念,其一般形式为 l[start:end:step],其中 start 和 end 分别是开始和结束索引,step 是在切片时要跨过的条目数量。此外,还可以对结束索引使用负值,即从序列的结尾往回计数。另一个有用的功能是以一种很合适的方式处理错误(如超过序列的长度)。如前一个例子所示,您还可以选择忽略切片中使用的三个值中的一个或多个值。例如,我在切片 l[0::2] 中没有使用结束索引。 可变的序列 在本文的开头,我提到过 list 和 tuple 之间的主要区别在于 list 是一个可变的序列,这就意味着您不但可以方便地访问 list 中的条目,而且可以方便地修改它们。但这会引起一个并发症状:您只能修改序列中的条目。若要向序列中添加条目(而不仅仅是修改条目),可使用 append 方法,如清单 5 所示。 清单 5. 修改 list 正如前一个例子所演示的,尝试修改不存在的 list 条目会导致出现错误。这一点意义重大,并演示了 Python 方法生成错误的情况。当问题较为严重时,将会产生一个错误,如果问题较小并且可以很容易地处理,则忽略它。 异构的可变序列 您可能想了解更为复杂的修改。通过综合切片知识以及如何修改 list 的知识,您应该已经获得了非常重要的见识:可以通过多种方式修改列表。就像 tuple 一样,list 也可以持有不同类型的数据(或不同类型的对象),这就是我所说的异构的可变序列。这两种功能在清单 6 中进行了更完整的描述。 清单 6. 异构的可变 list 修改 list 中的条目相当容易:您可以适当地设置条目的值,甚至设置成另一种不同的类型,如 string 或另一 list。您还可以使用重复运算符,可以将该运算符识别为乘法运算符,以便从小片段中构建更大的列表。 前面的例子向您展示了如何向 list 中添加元素,以及如何修改 list 中的条目。前一个例子还演示了如何从 list 中删除对象。删除条目的第一个方法是使用 del 方法。使用此方法可以删除一个条目或一个条目范围。您还可以使用灵活而强大的切片方法从 list 中删除切片。 |