3.2. 标准类型层级结构

以下是 Python 内置类型的列表。扩展模块 (具体实现会以 C, Java 或其他语言编写) 可以定义更多的类型。未来版本的 Python 可能会加入更多的类型 (例如有理数、高效存储的整型数组等等),不过新增类型往往都是通过标准库来提供的。

以下部分类型的描述中包含有 '特殊属性列表' 段落。这些属性提供对具体实现的访问而非通常使用。它们的定义在未来可能会改变。

  • None
  • 此类型只有一种取值。是一个具有此值的单独对象。此对象通过内置名称 None 访问。在许多情况下它被用来表示空值,例如未显式指明返回值的函数将返回 None。它的逻辑值为假。

  • NotImplemented

  • 此类型只有一种取值。是一个具有此值的单独对象。此对象通过内置名称 NotImplemented 访问。数值方法和丰富比较方法如未实现指定运算符表示的运算则应返回此值。(解释器会根据指定运算符继续尝试反向运算或其他回退操作)。它的逻辑值为真。

详情参见 实现算数运算

  • Ellipsis
  • 此类型只有一种取值。是一个具有此值的单独对象。此对象通过字面值 或内置名称 Ellipsis 访问。它的逻辑值为真。

  • numbers.Number

  • 此类对象由数字字面值创建,并会被作为算术运算符和算术内置函数的返回结果。数字对象是不可变的;一旦创建其值就不再改变。Python 中的数字当然非常类似数学中的数字,但也受限于计算机中的数字表示方法。

Python 区分整型数、浮点型数和复数:

  • numbers.Integral
  • 此类对象表示数学中整数集合的成员 (包括正数和负数)。

整型数可细分为两种类型:

整型 (int)

此类对象表示任意大小的数字,仅受限于可用的内存 (包括虚拟内存)。在变换和掩码运算中会以二进制表示,负数会以 2 的补码表示,看起来像是符号位向左延伸补满空位。

  1. - 布尔型 ([<code>bool</code>](https://docs.python.org/zh-cn/3.7/library/functions.html#bool))
  2. -

此类对象表示逻辑值 False 和 True。代表 FalseTrue 值的两个对象是唯二的布尔对象。布尔类型是整型的子类型,两个布尔值在各种场合的行为分别类似于数值 0 和 1,例外情况只有在转换为字符串时分别返回字符串 "False""True"

整型数表示规则的目的是在涉及负整型数的变换和掩码运算时提供最为合理的解释。

  • numbers.Real (float)
  • 此类对象表示机器级的双精度浮点数。其所接受的取值范围和溢出处理将受制于底层的机器架构 (以及 C 或 Java 实现)。Python 不支持单精度浮点数;支持后者通常的理由是节省处理器和内存消耗,但这点节省相对于在 Python 中使用对象的开销来说太过微不足道,因此没有理由包含两种浮点数而令该语言变得复杂。

  • numbers.Complex (complex)

  • 此类对象以一对机器级的双精度浮点数来表示复数值。有关浮点数的附带规则对其同样有效。一个复数值 z 的实部和虚部可通过只读属性 z.realz.imag 来获取。
  • 序列
  • 此类对象表示以非负整数作为索引的有限有序集。内置函数 len() 可返回一个序列的条目数量。当一个序列的长度为 n 时,索引集包含数字 0, 1, …, n-1。序列 a 的条目 i 可通过 a[i] 选择。

序列还支持切片: a[i:j] 选择索引号为 k 的所有条目,i <= k < j。当用作表达式时,序列的切片就是一个与序列类型相同的新序列。新序列的索引还是从 0 开始。

有些序列还支持带有第三个 "step" 形参的 "扩展切片": a[i:j:k] 选择 a 中索引号为 x 的所有条目,x = i + n*k, n >= 0i <= x < j

序列可根据其可变性来加以区分:

  • 不可变序列
  • 不可变序列类型的对象一旦创建就不能再改变。(如果对象包含对其他对象的引用,其中的可变对象就是可以改变的;但是,一个不可变对象所直接引用的对象集是不能改变的。)

以下类型属于不可变对象:

  1. - 字符串
  2. -

字符串是由 Unicode 码位值组成的序列。范围在 U+0000 - U+10FFFF 之内的所有码位值都可在字符串中使用。Python 没有 char 类型;而是将字符串中的每个码位表示为一个长度为 1 的字符串对象。内置函数 ord() 可将一个码位由字符串形式转换成一个范围在 0 - 10FFFF 之内的整型数;chr() 可将一个范围在 0 - 10FFFF 之内的整型数转换为长度为 1 的对应字符串对象。str.encode() 可以使用指定的文本编码将 str 转换为 bytes,而 bytes.decode() 则可以实现反向的解码。

  1. - 元组
  2. -

一个元组中的条目可以是任意 Python 对象。包含两个或以上条目的元组由逗号分隔的表达式构成。只有一个条目的元组 ('单项元组') 可通过在表达式后加一个逗号来构成 (一个表达式本身不能创建为元组,因为圆括号要用来设置表达式分组)。一个空元组可通过一对内容为空的圆括号创建。

  1. - 字节串
  2. -

字节串对象是不可变的数组。其中每个条目都是一个 8 位字节,以取值范围 0 <= x < 256 的整型数表示。字节串字面值 (例如 b'abc') 和内置的 bytes() 构造器可被用来创建字节串对象。字节串对象还可以通过 decode() 方法解码为字符串。

  • 可变序列
  • 可变序列在被创建后仍可被改变。下标和切片标注可被用作赋值和 del (删除) 语句的目标。

目前有两种内生可变序列类型:

  1. - 列表
  2. -

列表中的条目可以是任意 Python 对象。列表由用方括号括起并由逗号分隔的多个表达式构成。(注意创建长度为 0 或 1 的列表无需使用特殊规则。)

  1. - 字节数组
  2. -

字节数组对象属于可变数组。可以通过内置的 bytearray() 构造器来创建。除了是可变的 (因而也是不可哈希的),在其他方面字节数组提供的接口和功能都于不可变的 bytes 对象一致。

扩展模块 array 提供了一个额外的可变序列类型示例,collections 模块也是如此。

  • 集合类型
  • 此类对象表示由不重复且不可变对象组成的无序且有限的集合。因此它们不能通过下标来索引。但是它们可被迭代,也可用内置函数 len() 返回集合中的条目数。集合常见的用处是快速成员检测,去除序列中的重复项,以及进行交、并、差和对称差等数学运算。

对于集合元素所采用的不可变规则与字典的键相同。注意数字类型遵循正常的数字比较规则: 如果两个数字相等 (例如 11.0),则同一集合中只能包含其中一个。

目前有两种内生集合类型:

  • 集合
  • 此类对象表示可变集合。它们可通过内置的 set() 构造器创建,并且创建之后可以通过方法进行修改,例如 add()

  • 冻结集合

  • 此类对象表示不可变集合。它们可通过内置的 frozenset() 构造器创建。由于 frozenset 对象不可变且 hashable,它可以被用作另一个集合的元素或是字典的键。
  • 映射
  • 此类对象表示由任意索引集合所索引的对象的集合。通过下标 a[k] 可在映射 a 中选择索引为 k 的条目;这可以在表达式中使用,也可作为赋值或 del 语句的目标。内置函数 len() 可返回一个映射中的条目数。

目前只有一种内生映射类型:

  • 字典
  • 此类对象表示由几乎任意值作为索引的有限个对象的集合。不可作为键的值类型只有包含列表或字典或其他可变类型,通过值而非对象编号进行比较的值,其原因在于高效的字典实现需要使用键的哈希值以保持一致性。用作键的数字类型遵循正常的数字比较规则: 如果两个数字相等 (例如 11.0) 则它们均可来用来索引同一个字典条目。

字典是可变的;它们可通过 {…} 标注来创建 (参见 字典显示 小节)。

扩展模块 dbm.ndbmdbm.gnu 提供了额外的映射类型示例,collections 模块也是如此。

  • 可调用类型
  • 此类型可以被应用于函数调用操作 (参见 调用 小节):

    • 用户定义函数
    • 用户定义函数对象可通过函数定义来创建 (参见 函数定义 小节)。它被调用时应附带一个参数列表,其中包含的条目应与函数所定义的形参列表一致。

特殊属性:

属性

含义

doc

该函数的文档字符串,没有则为 None;不会被子类继承。

可写

name

该函数的名称。

可写

qualname

该函数的 qualified name

3.3 新版功能.

可写

module

该函数所属模块的名称,没有则为 None

可写

defaults

由具有默认值的参数的默认参数值组成的元组,如无任何参数具有默认值则为 None

可写

code

表示编译后的函数体的代码对象。

可写

globals

对存放该函数中全局变量的字典的引用 —- 函数所属模块的全局命名空间。

只读

dict

命名空间支持的函数属性。

可写

closure

None 或包含该函数可用变量的绑定的单元的元组。有关 cell_contents 属性的详情见下。

只读

annotations

包含参数标注的字典。字典的键是参数名,如存在返回标注则为 'return'

可写

kwdefaults

仅包含关键字参数默认值的字典。

可写

大部分标有 "Writable" 的属性均会检查赋值的类型。

函数对象也支持获取和设置任意属性,例如这可以被用来给函数附加元数据。使用正规的属性点号标注获取和设置此类属性。注意当前实现仅支持用户定义函数属性。未来可能会增加支持内置函数属性。

单元对象具有 cell_contents 属性。这可被用来获取以及设置单元的值。

有关函数定义的额外信息可以从其代码对象中提取;参见下文对内部类型的描述。

  • 实例方法
  • 实例方法用于结合类、类实例和任何可调用对象 (通常为用户定义函数)。

特殊的只读属性: self 为类实例对象本身,func 为函数对象;doc 为方法的文档 (与 func.doc 作用相同);name 为方法名称 (与 func.name 作用相同);module 为方法所属模块的名称,没有则为 None

方法还支持获取 (但不能设置) 下层函数对象的任意函数属性。

用户定义方法对象可在获取一个类的属性时被创建 (也可能通过该类的一个实例),如果该属性为用户定义函数对象或类方法对象。

当通过从类实例获取一个用户定义函数对象的方式创建一个实例方法对象时,类实例对象的 self 属性即为该实例,并会绑定方法对象。该新建方法的 func 属性就是原来的函数对象。

当通过从类或实例获取另一个方法对象的方式创建一个用户定义方法对象时,其行为将等同于一个函数对象,例外的只有新实例的 func 属性将不是原来的方法对象,而是其 func 属性。

当通过从类或实例获取一个类方法对象的方式创建一个实例对象时,实例对象的 self 属性为该类本身,其 func 属性为类方法对应的下层函数对象。

当一个实例方法对象被调用时,会调用对应的下层函数 (func),并将类实例 (self) 插入参数列表的开头。例如,当 C 是一个包含了 f() 函数定义的类,而 xC 的一个实例,则调用 x.f(1) 就等同于调用 C.f(x, 1)

当一个实例方法对象是衍生自一个类方法对象时,保存在 self 中的 "类实例" 实际上会是该类本身,因此无论是调用 x.f(1) 还是 C.f(1) 都等同于调用 f(C,1),其中 f 为对应的下层函数。

请注意从函数对象到实例方法对象的变换会在每一次从实例获取属性时发生。在某些情况下,一种高效的优化方式是将属性赋值给一个本地变量并调用该本地变量。还要注意这样的变换只发生于用户定义函数;其他可调用对象 (以及所有不可调用对象) 在被获取时都不会发生变换。还有一个需要关注的要点是作为一个类实例属性的用户定义函数不会被转换为绑定方法;这样的变换 仅当 函数是类属性时才会发生。

  • 生成器函数
  • 一个使用 yield 语句 (见 yield 语句 章节)的函数或方法被称作一个 生成器函数。 这样的函数在被调用时,总是返回一个可以执行函数体的迭代器对象:调用该迭代器的 iterator.next() 方法将会导致这个函数一直运行直到它使用 yield 语句提供了一个值为止。 当这个函数执行 return 语句或者执行到末尾时,将引发 StopIteration 异常并且这个迭代器将到达所返回的值集合的末尾。

  • 协程函数

  • 使用 async def 来定义的函数或方法就被称为 协程函数。这样的函数在被调用时会返回一个 coroutine 对象。它可能包含 await 表达式以及 async withasync for 语句。详情可参见 协程对象 一节。

  • 异步生成器函数

  • 使用 async def 来定义并包含 yield 语句的函数或方法就被称为 异步生成器函数。这样的函数在被调用时会返回一个异步迭代器对象,该对象可在 async for 语句中用来执行函数体。

调用异步迭代器的 aiterator.anext() 方法将会返回一个 awaitable,此对象会在被等待时执行直到使用 yield 表达式输出一个值。当函数执行时到空的 return 语句或是最后一条语句时,将会引发 StopAsyncIteration 异常,异步迭代器也会到达要输出的值集合的末尾。

  • 内置函数
  • 内置函数对象是对于 C 函数的外部封装。内置函数的例子包括 len()math.sin() (math 是一个标准内置模块)。内置函数参数的数量和类型由 C 函数决定。特殊的只读属性: doc 是函数的文档字符串,如果没有则为 None; name 是函数的名称; self 设定为 None (参见下一条目); module 是函数所属模块的名称,如果没有则为 None

  • 内置方法

  • 此类型实际上是内置函数的另一种形式,只不过还包含了一个传入 C 函数的对象作为隐式的额外参数。内置方法的一个例子是 alist.append(),其中 alist 为一个列表对象。在此示例中,特殊的只读属性 self 会被设为 alist 所标记的对象。

  • 类是可调用的。此种对象通常是作为“工厂”来创建自身的实例,类也可以有重载 new() 的变体类型。调用的参数会传给 new(),而且通常也会传给 init() 来初始化新的实例。

  • 类实例

  • 任意类的实例通过在所属类中定义 call() 方法即能成为可调用的对象。
  • 模块
  • 模块是 Python 代码的基本组织单元,由 导入系统 创建,由 import 语句发起调用,或者通过 importlib.import_module() 和内置的 import() 等函数发起调用。 模块对象具有由字典对象实现的命名空间(这是被模块中定义的函数的 globals 属性引用的字典)。 属性引用被转换为该字典中的查找,例如 m.x 相当于 m.dict["x"]。 模块对象不包含用于初始化模块的代码对象(因为初始化完成后不需要它)。

属性赋值会更新模块的命名空间字典,例如 m.x = 1 等同于 m.dict["x"] = 1

预定义的 (可写) 属性: name 为模块的名称; doc 为模块的文档字符串,如果没有则为 None; annotations (可选) 为一个包含 变量标注 的字典,它是在模块体执行时获取的; file 是模块对应的被加载文件的路径名,如果它是加载自一个文件的话。某些类型的模块可能没有 file 属性,例如 C 模块是静态链接到解释器内部的; 对于从一个共享库动态加载的扩展模块来说该属性为该共享库文件的路径名。

特殊的只读属性: dict 为以字典对象表示的模块命名空间。

CPython implementation detail: 由于 CPython 清理模块字典的设定,当模块离开作用域时模块字典将会被清理,即使该字典还有活动的引用。想避免此问题,可复制该字典或保持模块状态以直接使用其字典。

  • 自定义类
  • 自定义类这种类型一般通过类定义来创建 (参见 类定义 一节)。每个类都有通过一个字典对象实现的独立命名空间。类属性引用会被转化为在此字典中查找,例如 C.x 会被转化为 C.dict["x"] (不过也存在一些钩子对象以允许其他定位属性的方式)。当未在其中发现某个属性名称时,会继续在基类中查找。这种基类查找使用 C3 方法解析顺序,即使存在 '钻石形' 继承结构即有多条继承路径连到一个共同祖先也能保持正确的行为。有关 Python 使用的 C3 MRO 的详情可查看配合 2.3 版发布的文档 https://www.python.org/download/releases/2.3/mro/.

当一个类属性引用 (假设类名为 C) 会产生一个类方法对象时,它将转化为一个 self 属性为 C 的实例方法对象。当其会产生一个静态方法对象时,它将转化为该静态方法对象所封装的对象。从类的 dict 所包含内容以外获取属性的其他方式请参看 实现描述器 一节。

类属性赋值会更新类的字典,但不会更新基类的字典。

类对象可被调用 (见上文) 以产生一个类实例 (见下文)。

特殊属性: name 为类的名称; module 为类所在模块的名称; dict 为包含类命名空间的字典; bases 为包含基类的元组,按其在基类列表中的出现顺序排列; doc 为类的文档字符串,如果没有则为 None; annotations (可选) 为一个包含 变量标注 的字典,它是在类体执行时获取的。

  • 类实例
  • 类实例可通过调用类对象来创建 (见上文)。每个类实例都有通过一个字典对象实现的独立命名空间,属性引用会首先在此字典中查找。当未在其中发现某个属性,而实例对应的类中有该属性时,会继续在类属性中查找。如果找到的类属性为一个用户定义函数对象,它会被转化为实例方法对象,其 self 属性即该实例。静态方法和类方法对象也会被转化;参见上文 "Classes" 一节。要了解其他通过类实例来获取相应类属性的方式可参见 实现描述器 一节,这样得到的属性可能与实际存放于类的 dict 中的对象不同。如果未找到类属性,而对象对应的类具有 getattr() 方法,则会调用该方法来满足查找要求。

属性赋值和删除会更新实例的字典,但不会更新对应类的字典。如果类具有 setattr()delattr() 方法,则将调用方法而不再直接更新实例的字典。

如果类实例具有某些特殊名称的方法,就可以伪装为数字、序列或映射。参见 特殊方法名称 一节。

特殊属性: dict 为属性字典; class 为实例对应的类。

  • I/O 对象 (或称文件对象)
  • file object 表示一个打开的文件。有多种快捷方式可用来创建文件对象: open() 内置函数,以及 os.popen(), os.fdopen() 和 socket 对象的 makefile() 方法 (还可能使用某些扩展模块所提供的其他函数或方法)。

sys.stdin, sys.stdoutsys.stderr 会初始化为对应于解释器标准输入、输出和错误流的文件对象;它们都会以文本模式打开,因此都遵循 io.TextIOBase 抽象类所定义的接口。

  • 内部类型
  • 某些由解释器内部使用的类型也被暴露给用户。它们的定义可能随未来解释器版本的更新而变化,为内容完整起见在此处一并介绍。

    • 代码对象
    • 代码对象表示 编译为字节的 可执行 Python 代码,或称 bytecode。代码对象和函数对象的区别在于函数对象包含对函数全局对象 (函数所属的模块) 的显式引用,而代码对象不包含上下文;而且默认参数值会存放于函数对象而不是代码对象内 (因为它们表示在运行时算出的值)。与函数对象不同,代码对象不可变,也不包含对可变对象的引用 (不论是直接还是间接)。

特殊的只读属性: co_name 为函数名称; co_argcount 为位置参数的数量 (包括有默认值的参数); co_nlocals 为函数使用的本地变量数量 (包括参数); co_varnames 为一个包含本地变量名称的元组 (以参数名打头); co_cellvars 为一个包含被嵌套函数所引用的本地变量名称的元组; co_freevars 为一个包含自由变量的元组; co_code 为一个表示字节码指令序列的字符串; co_consts 为一个包含字节码所使用的字面值的元组; co_names 为一个包含字节码所使用的名称的元组; co_filename 为被编译代码所在的文件名; co_firstlineno 为函数首行的行号; co_lnotab 为一个以编码表示的从字节码偏移量到行号的映射的字符串 (详情参见解释器的源码); co_stacksize 为要求的栈大小 (包括本地变量); co_flags 为一个以编码表示的多个解释器所用标志的整型数。

以下是可用于 co_flags 的标志位定义:如果函数使用 arguments 语法来接受任意数量的位置参数,则 0x04 位被设置;如果函数使用 *keywords 语法来接受任意数量的关键字参数,则 0x08 位被设置;如果函数是一个生成器,则 0x20 位被设置。

未来特性声明 (from future import division) 也使用 co_flags 中的标志位来指明代码对象的编译是否启用特定的特性: 如果函数编译时启用未来除法特性则设置 0x2000 位; 在更早的 Python 版本中则使用 0x100x1000 位。

co_flags 中的其他位被保留为内部使用。

如果代码对象表示一个函数,co_consts 中的第一项将是函数的文档字符串,如果未定义则为 None

  • 帧对象
  • 帧对象表示执行帧。它们可能出现在回溯对象中 (见下文),还会被传递给注册跟踪函数。

特殊的只读属性: f_back 为前一堆栈帧 (指向调用者),如是最底层堆栈帧则为 None; f_code 为此帧中所执行的代码对象; f_locals 为用于查找本地变量的字典; f_globals 则用于查找全局变量; f_builtins 用于查找内置 (固有) 名称; f_lasti 给出精确指令 (这是代码对象的字节码字符串的一个索引)。

特殊的可写属性: f_trace,如果不为 None,则是在代码执行期间调用各类事件的函数 (由调试器使用)。通常每个新源码行会触发一个事件 - 这可以通过将 f_trace_lines 设为 False 来禁用。

具体的实现 可能 会通过将 f_trace_opcodes 设为 True 来允许按操作码请求事件。请注意如果跟踪函数引发的异常逃逸到被跟踪的函数中,这可能会导致未定义的解释器行为。

f_lineno 为帧的当前行号 —- 在这里写入从一个跟踪函数内部跳转的指定行 (仅用于最底层的帧)。调试器可以通过写入 f_lineno 实现一个 Jump 命令 (即设置下一语句)。

帧对象支持一个方法:

  1. - <code>frame.</code><code>clear</code>()[](https://docs.python.org/zh-cn/3.7/reference/#frame.clear)
  2. -

此方法清除该帧持有的全部对本地变量的引用。而且如果该帧属于一个生成器,生成器会被完成。这有助于打破包含帧对象的循环引用 (例如当捕获一个异常并保存其回溯在之后使用)。

如果该帧当前正在执行则会引发 RuntimeError

3.4 新版功能.

  • 回溯对象
  • 回溯对象表示一个异常的栈跟踪记录。当异常发生时会隐式地创建一个回溯对象,也可能通过调用 types.TracebackType 显式地创建。

对于隐式地创建的回溯对象,当查找异常句柄使得执行栈展开时,会在每个展开层级的当前回溯之前插入一个回溯对象。当进入一个异常句柄时,栈跟踪将对程序启用。(参见 try 语句 一节。) 它可作为 sys.excinfo() 所返回的元组的第三项,以及所捕获异常的 _traceback 属性被获取。

当程序不包含可用的句柄时,栈跟踪会 (以良好的格式) 写入标准错误流;如果解释器处于交互模式,它也可作为 sys.last_traceback 对用户启用。

对于显式创建的回溯对象,则由回溯对象的创建者来决定应该如何链接 tb_next 属性来构成完整的栈跟踪。

特殊的只读属性: tb_frame 指向当前层级的执行帧; tb_lineno 给出发生异常所在的行号; tb_lasti 标示具体指令。如果异常发生于没有匹配的 except 子句或有 finally 子句的 try 语句中,回溯对象中的行号和最后指令可能与相应帧对象中行号不同。

特殊的可写属性: tb_next 为栈跟踪中的下一层级 (通往发生异常的帧),如果没有下一层级则为 None

在 3.7 版更改: 回溯对象现在可以使用 Python 代码显式地实例化,现有实例的 tb_next 属性可以被更新。

  • 切片对象
  • 切片对象用来表示 getitem() 方法得到的切片。该对象也可使用内置的 slice() 函数来创建。

特殊的只读属性: start 为下界; stop 为上界; step 为步长值; 各值如省略则为 None。这些属性可具有任意类型。

切片对象支持一个方法:

  1. - <code>slice.</code><code>indices</code>(_self_, _length_)[](https://docs.python.org/zh-cn/3.7/reference/#slice.indices)
  2. -

此方法接受一个整型参数 length 并计算在切片对象被应用到 length 指定长度的条目序列时切片的相关信息应如何描述。其返回值为三个整型数组成的元组;这些数分别为切片的 startstop 索引号以及 step 步长值。索引号缺失或越界则按照正规连续切片的方式处理。

  • 静态方法对象
  • 静态方法对象提供了一种避免上文所述将函数对象转换为方法对象的方式。静态方法对象为对任意其他对象的封装,通常用来封装用户定义方法对象。当从类或类实例获取一个静态方法对象时,实际返回的对象是封装的对象,它不会被进一步转换。静态方法对象自身不是可调用的,但它们所封装的对象通常都是可调用的。静态方法对象可通过内置的 staticmethod() 构造器来创建。

  • 类方法对象

  • 类方法对象和静态方法一样是对其他对象的封装,会改变从类或类实例获取该对象的方式。类方法对象在此类获取操作中的行为已在上文 "用户定义方法" 一节中描述。类方法对象可通过内置的 classmethod() 构造器来创建。