3. 数据模型
3.1. 对象、值与类型
对象 是 Python 中对数据的抽象。 Python 程序中的所有数据都是由对象或对象间关系来表示的。 (从某种意义上说,按照冯·诺依曼的“存储程序计算机”模型,代码本身也是由对象来表示的。)
每个对象都有相应的标识号、类型和值。 一个对象被创建后它的 标识号 就绝不会改变;你可以将其理解为该对象在内存中的地址。 is
运算符比较两个对象的标识号是否相同;id()
函数返回一个代表其标识号的整数。
在 CPython 中,id(x)
就是存放 x
的内存的地址。
对象的类型决定该对象所支持的操作 (例如 "对象是否有长度属性?") 并且定义了该类型的对象可能的取值。type()
函数能返回一个对象的类型 (类型本身也是对象)。与编号一样,一个对象的 类型 也是不可改变的。[1]
有些对象的 值 可以改变。值可以改变的对象被称为 可变对象;值不可以改变的对象就被称为 不可变对象。(一个不可变容器对象如果包含对可变对象的引用,当后者的值改变时,前者的值也会改变;但是该容器仍属于不可变对象,因为它所包含的对象集是不会改变的。因此,不可变并不严格等同于值不能改变,实际含义要更微妙。) 一个对象的可变性是由其类型决定的;例如,数字、字符串和元组是不可变的,而字典和列表是可变的。
对象绝不会被显式地销毁;然而,当无法访问时它们可能会被作为垃圾回收。允许具体的实现推迟垃圾回收或完全省略此机制 —- 如何实现垃圾回收是实现的质量问题,只要可访问的对象不会被回收即可。
CPython 目前使用带有 (可选) 延迟检测循环链接垃圾的引用计数方案,会在对象不可访问时立即回收其中的大部分,但不保证回收包含循环引用的垃圾。请查看 gc
模块的文档了解如何控制循环垃圾的收集相关信息。其他实现会有不同的行为方式,CPython 现有方式也可能改变。不要依赖不可访问对象的立即终结机制 (所以你应当总是显式地关闭文件)。
注意:使用实现的跟踪或调试功能可能令正常情况下会被回收的对象继续存活。还要注意通过 try
…except
语句捕捉异常也可能令对象保持存活。
有些对象包含对“外部”资源如打开的文件或窗口的引用。 当对象被作为垃圾回收时这些资源也应该会被释放,但由于垃圾回收并不确保发生,这些对象还提供了明确地释放外部资源的操作,通常为一个 close()
方法。 强烈推荐在程序中显式关闭此类对象。 try
…finally
语句和 with
语句提供了进行此种操作的更便捷方式。
有些对象包含对其他对象的引用;它们被称为 容器。容器的例子有元组、列表和字典等。这些引用是容器对象值的组成部分。在多数情况下,当谈论一个容器的值时,我们是指所包含对象的值而不是其编号;但是,当我们谈论一个容器的可变性时,则仅指其直接包含的对象的编号。因此,如果一个不可变容器 (例如元组) 包含对一个可变对象的引用,则当该可变对象被改变时容器的值也会改变。
类型会影响对象行为的几乎所有方面。 甚至对象标识号的重要性也在某种程度上受到影响:对于不可变类型,计算新值的操作实际上可能返回一个指向具有相同类型和值的任何现存对象的引用,而对于可变对象来说这是不允许的。 例如在 a = 1; b = 1
之后,a 和 b 可能会也可能不会指向同一个值为一的对象。 这是因为 int
是不可变对象,因此对 1
的引用可以被重用。 此行为依赖于所使用的具体实现,因此不应该依赖它,而在使用对象标识测试时需要注意。 不过,在 c = []; d = []
之后,c 和 d 保证会指向两个不同的、独特的、新创建的空列表。 (注意 e = f = []
会将 同一个 对象同时赋值给 e 和 f。)
3.2. 标准类型层级结构
以下是 Python 内置类型的列表。扩展模块 (具体实现会以 C, Java 或其他语言编写) 可以定义更多的类型。未来版本的 Python 可能会加入更多的类型 (例如有理数、高效存储的整型数组等等),不过新增类型往往都是通过标准库来提供的。
以下部分类型的描述中包含有 '特殊属性列表' 段落。这些属性提供对具体实现的访问而非通常使用。它们的定义在未来可能会改变。
3.2.1. None
此类型只有一种取值。是一个具有此值的单独对象。此对象通过内置名称 None
访问。在许多情况下它被用来表示空值,例如未显式指明返回值的函数将返回 None。它的逻辑值为假。
3.2.2. NotImplemented
此类型只有一种取值。 是一个具有该值的单独对象。 此对象通过内置名称 NotImplemented
访问。 数值方法和丰富比较方法如未实现指定运算符表示的运算则应返回该值。 (解释器会根据具体运算符继续尝试反向运算或其他回退操作。) 它不应被解读为布尔值。
详情参见 实现算术运算。
在 3.9 版本发生变更: 对 NotImplemented
求布尔值的操作已被弃用。 虽然它目前会被求解为真值,但将同时发出 DeprecationWarning
。 它将在未来的 Python 版本中引发 TypeError
。
3.2.3. Ellipsis
此类型只有一种取值。是一个具有此值的单独对象。此对象通过字面值 …
或内置名称 Ellipsis
访问。它的逻辑值为真。
3.2.4. numbers.Number
此类对象由数字字面值创建,并会被作为算术运算符和算术内置函数的返回结果。数字对象是不可变的;一旦创建其值就不再改变。Python 中的数字当然非常类似数学中的数字,但也受限于计算机中的数字表示方法。
数字类的字符串表示形式,由 __repr__()
和 __str__()
算出,具有以下特征属性:
它们是有效的数字字面值,当被传给它们的类构造器时,将会产生具有原数字值的对象。
表示形式会在可能的情况下采用 10 进制。
开头的零,除小数点前可能存在的单个零之外,将不会被显示。
末尾的零,除小数点后可能存在的单个零之外,将不会被显示。
正负号仅在当数字为负值时会被显示。
Python 区分整型数、浮点型数和复数:
3.2.4.1. numbers.Integral
此类对象表示数学中整数集合的成员 (包括正数和负数)。
备注
整型数表示规则的目的是在涉及负整型数的变换和掩码运算时提供最为合理的解释。
整型数可细分为两种类型:
- 整型 (
int
) 此类对象表示任意大小的数字,仅受限于可用的内存 (包括虚拟内存)。在变换和掩码运算中会以二进制表示,负数会以 2 的补码表示,看起来像是符号位向左延伸补满空位。
布尔型 (
bool
)- 此类对象表示逻辑值 False 和 True。代表
False
和True
值的两个对象是唯二的布尔对象。布尔类型是整型的子类型,两个布尔值在各种场合的行为分别类似于数值 0 和 1,例外情况只有在转换为字符串时分别返回字符串"False"
或"True"
。
3.2.4.2. numbers.Real
(float
)
此类对象表示机器级的双精度浮点数。其所接受的取值范围和溢出处理将受制于底层的机器架构 (以及 C 或 Java 实现)。Python 不支持单精度浮点数;支持后者通常的理由是节省处理器和内存消耗,但这点节省相对于在 Python 中使用对象的开销来说太过微不足道,因此没有理由包含两种浮点数而令该语言变得复杂。
3.2.4.3. numbers.Complex
(complex
)
此类对象以一对机器级的双精度浮点数来表示复数值。有关浮点数的附带规则对其同样有效。一个复数值 z
的实部和虚部可通过只读属性 z.real
和 z.imag
来获取。
3.2.5. 序列
这些代表以非负数为索引的有限有序集合。 内置函数 len()
将返回序列的项数。 当序列 的长度为 n 时,索引集合将包含数字 0, 1, …, n-1。 a[i]
是选择序列 a 中的第 i 项。 某些序列,包括内置的序列,可通过加上序列长度来解读负下标值。 例如,a[-2]
等价于 a[n-2]
,即长度为 n
的 a 序列的倒数第二项。
序列还支持切片: a[i:j]
是选择索引为 k 使得 i <=
k <
j 的所有条目。 当用作表达式时,切片就是一个相同类型的新序列。 以上有关负索引的注释也适用于切片位置的负值。
有些序列还支持带有第三个 "step" 形参的 "扩展切片": a[i:j:k]
选择 a 中索引号为 x 的所有条目,x = i + n*k
, n >=
0
且 i <=
x <
j。
序列可根据其可变性来加以区分:
3.2.5.1. 不可变序列
不可变序列类型的对象一旦创建就不能再改变。(如果对象包含对其他对象的引用,其中的可变对象就是可以改变的;但是,一个不可变对象所直接引用的对象集是不能改变的。) 以下类型属于不可变对象:
- 字符串
字符串是由代表 Unicode 码位的值组成的序列。 取值范围在
U+0000 - U+10FFFF
之内的所有码位都可在字符串中使用。 Python 没有 char 类型;而是将字符串中的每个码位表示为一个长度为1
的字符串对象。 内置函数ord()
可将一个码位由字符串形式转换为取值范围在0 - 10FFFF
之内的整数;chr()
可将一个取值范围在0 - 10FFFF
之内的整数转换为长度为1
的对应字符串对象。str.encode()
可以使用给定的文本编码格式将str
转换为bytes
,而bytes.decode()
则可以被用来实现相反的解码操作。元组
一个元组中的条目可以是任意 Python 对象。包含两个或以上条目的元组由逗号分隔的表达式构成。只有一个条目的元组 ('单项元组') 可通过在表达式后加一个逗号来构成 (一个表达式本身不能创建为元组,因为圆括号要用来设置表达式分组)。一个空元组可通过一对内容为空的圆括号创建。
字节串
- 字节串对象是不是变的数组。 其中的条目是 8 比特位的字节,以取值范围 0 <= x < 256 内的整数表示。 字节串字面值 (如
b'abc'
) 和内置的bytes()
构造器可被用来创建字节串对象。 并且,字节串对象还可通过decode()
方法被解码为字符串。
3.2.5.2. 可变序列
可变序列在被创建后仍可被改变。下标和切片标注可被用作赋值和 del
(删除) 语句的目标。
备注
collections
和 array
模块提供了可变序列类型的更多例子。
目前有两种内生可变序列类型:
- 列表
列表中的条目可以是任意 Python 对象。列表由用方括号括起并由逗号分隔的多个表达式构成。(注意创建长度为 0 或 1 的列表无需使用特殊规则。)
字节数组
- 字节数组对象属于可变数组。可以通过内置的
bytearray()
构造器来创建。除了是可变的 (因而也是不可哈希的),在其他方面字节数组提供的接口和功能都与不可变的bytes
对象一致。
3.2.6. 集合类型
此类对象表示由不重复且不可变对象组成的无序且有限的集合。因此它们不能通过下标来索引。但是它们可被迭代,也可用内置函数 len()
返回集合中的条目数。集合常见的用处是快速成员检测,去除序列中的重复项,以及进行交、并、差和对称差等数学运算。
对于集合元素所采用的不可变规则与字典的键相同。注意数字类型遵循正常的数字比较规则: 如果两个数字相等 (例如 1
和 1.0
),则同一集合中只能包含其中一个。
目前有两种内生集合类型:
- 集合
此类对象表示可变集合。它们可通过内置的
set()
构造器创建,并且创建之后可以通过方法进行修改,例如add()
。冻结集合
- 此类对象表示不可变集合。它们可通过内置的
frozenset()
构造器创建。由于 frozenset 对象不可变且 hashable,它可以被用作另一个集合的元素或是字典的键。
3.2.7. 映射
此类对象表示由任意索引集合所索引的对象的集合。通过下标 a[k]
可在映射 a
中选择索引为 k
的条目;这可以在表达式中使用,也可作为赋值或 del
语句的目标。内置函数 len()
可返回一个映射中的条目数。
目前只有一种内生映射类型:
3.2.7.1. 字典
此类对象表示由几乎任意值作为索引的有限个对象的集合。不可作为键的值类型只有包含列表或字典或其他可变类型,通过值而非对象编号进行比较的值,其原因在于高效的字典实现需要使用键的哈希值以保持一致性。用作键的数字类型遵循正常的数字比较规则: 如果两个数字相等 (例如 1
和 1.0
) 则它们均可来用来索引同一个字典条目。
字典会保留插入顺序,这意味着键将以它们被添加的顺序在字典中依次产生。 替换某个现有的键不会改变其顺序,但是移除某个键再重新插入则会将其添加到末尾而不会保留其原有位置。
字典是可变对象;它们可通过 {}
标注方式来创建(参见 字典显示 一节)。
扩展模块 dbm.ndbm
和 dbm.gnu
提供了额外的映射类型示例,collections
模块也是如此。
在 3.7 版本发生变更: 在 Python 3.6 版之前字典不会保留插入顺序。 在 CPython 3.6 中插入顺序会被保留,但这在当时被当作是一个实现细节而非确定的语言特性。
3.2.8. 可调用类型
此类型可以被应用于函数调用操作 (参见 调用 小节):
3.2.8.1. 用户定义函数
用户定义函数对象可通过函数定义来创建 (参见 函数定义 小节)。它被调用时应附带一个参数列表,其中包含的条目应与函数所定义的形参列表一致。
3.2.8.1.1. 特殊的只读属性
属性 | 含意 |
---|---|
- function.globals - |
对存放该函数中 全局变量 的 字典 的引用 —— 函数定义所在模块的全局命名空间。
|
- function.closure - |
None 或单元的 tuple ,其中包含了名称在函数的 代码对象 的 co_freevars 中对指定名称的绑定。
单元对象具有 cell_contents 属性。这可被用来获取以及设置单元的值。
|
3.2.8.1.2. 特殊的可写属性
这些属性大多会检查赋值的类型:
属性 | 含意 |
---|---|
- function.doc - |
函数的文档字符串,或者如果不可用则为 None 。
|
- function.name - |
函数的名称。 另请参阅: __name__ 属性 。
|
- function.qualname - |
函数的 qualified name。 另请参阅: __qualname__ 属性 。
Added in version 3.3.
|
- function.module - |
该函数所属模块的名称,没有则为 None 。
|
- function.defaults - |
由具有默认值的形参的默认 parameter 值组成的 tuple ,或者如果无任何形参具有默认值则为 None 。
|
- function.code - | 代表已编译的函数体的 代码对象。 |
- function.dict - |
命名空间支持任意函数属性。 另请参阅: __dict__ 属性 。
|
- function.annotations - |
包含 形参 标注的 字典 。 该字典的键是形参名称,如存在返回标注则将包含 'return' 键。 另请参阅: 注解最佳实践。
|
- function.kwdefaults - |
包含仅限关键字 形参 默认值的 字典 。
|
- function.type_params - |
包含 泛型函数 类型形参 的 tuple 。
Added in version 3.12.
|
函数对象也支持获取和设置任意属性,举例来说,这可被用于将元数据关联到函数。 通常使用带点号的属性标注来获取和设置这样的属性。
CPython 目前的实现仅支持用户自定义函数上的函数属性。 未来可能会支持 内置函数 上的函数属性。
有关函数定义的额外信息可以从其 代码对象 中提取(可通过 __code__
属性来访问)。
3.2.8.2. 实例方法
实例方法用于结合类、类实例和任何可调用对象 (通常为用户定义函数)。
特殊的只读属性:
- method.self - | 指向方法所 绑定 的类实例对象。 |
- method.func - | 指向原本的 函数对象 |
- method.doc - |
方法的文档 (等同于 method.__func__.__doc__ )。 如果原始函数具有文档字符串则为一个 字符串 ,否则为 None 。
|
- method.name - |
方法名称(与 method.__func__.__name__ 相同)
|
- method.module - |
方法定义所在模块的名称,如不可用则为 None 。
|
方法还支持读取(但不能设置)下层 函数对象 的任意函数属性。
用户自定义方法对象可在获取一个类的属性(可能是通过该类的实例)时被创建,如果该属性是一个用户自定义 函数对象 或 classmethod
对象的话。
当通过从类的实例获取一个用户自定义 函数对象 的方式创建一个实例方法对象时,该方法对象的 __self__
属性即为该实例,而该方法对象将被称作已 绑定。 该新建方法的 __func__
属性将是原来的函数对象。
当通过从类或实例获取一个 classmethod
对象的方式创建一个实例方法对象时,该对象的 __self__
属性即为该类本身,而其 __func__
属性将是类方法对应的下层函数对象。
当一个实例方法被调用时,会调用对应的下层函数 (__func__
),并将类实例 (__self__
) 插入参数列表的开头。 例如,当 C
是一个包含 f()
函数定义的类,而 x
是 C
的一个实例,则调用 x.f(1)
就等价于调用 C.f(x, 1)
。
当一个实例方法对象是派生自一个 classmethod
对象时,保存在 __self__
中的“类实例”实际上会是该类本身,因此无论是调用 x.f(1)
还是 C.f(1)
都等同于调用 f(C,1)
,其中 f
为对应的下层函数。
需要重点关注的是作为类实例的属性的用户自定义函数不会被转换为绑定方法;这 只会 在函数是类的属性时才会发生。
3.2.8.3. 生成器函数
一个使用 yield
语句(见 yield 语句 章节)的函数或方法被称为 生成器函数。 这样的函数在被调用时,总是返回一个可以执行该函数体的 iterator 对象:调用该迭代器的 iterator.__next__()
方法将导致这个函数一直运行到它使用 yield
语句提供一个值。 当这个函数执行 return
语句或到达函数体末尾时,将引发 StopIteration
异常并且该迭代器将到达所返回的值集合的末尾。
3.2.8.4. 协程函数
使用 async def
来定义的函数或方法就被称为 协程函数。这样的函数在被调用时会返回一个 coroutine 对象。它可能包含 await
表达式以及 async with
和 async for
语句。详情可参见 协程对象 一节。
3.2.8.5. 异步生成器函数
使用 async def
来定义并使用了 yield
语句的函数或方法被称为 异步生成器函数。 这样的函数在被调用时,将返回一个 asynchronous iterator 对象,该对象可在 async for
语句中被用来执行函数体。
调用异步迭代器的 aiterator.__anext__
方法将返回一个 awaitable,此对象会在被等待时执行直到使用 yield
产生一个值。 当函数执行到空的 return
语句或函数末尾时,将会引发 StopAsyncIteration
异常并且异步迭代器也将到达要产生的值集合的末尾。
3.2.8.6. 内置函数
内置函数是针对特定 C 函数的包装器。 内置函数的例子包括 len()
和 math.sin()
等 (math
是一个标准内置模块)。 参数的数量和类型是由 C 函数确定的。 特殊的只读属性:
__doc__
是函数的文档字符串,或者如果不可用则为None
。 参见function.__doc__
。__name__
是函数的名称。 参见function.__name__
。__self__
被设为None
(但请参见下一项)。__module__
是函数定义所在模块的名称,或者如果不可用则为None
。 参见function.__module__
。
3.2.8.7. 内置方法
此类型实际上是内置函数的另一种形式,只不过还包含了一个转入 C 函数的对象作为隐式的额外参数。 内置方法的一个例子是 alist.append()
,其中 alist 是一个列表对象。 在此示例中,特殊的只读属性 __self__
会被设为 alist 所标记的对象。 (该属性的语义与 其他实例方法
的相同。)
3.2.8.8. 类
类是可调用对象。 这些对象通常是用作创建自身实例的“工厂”,但类也可以有重载 __new__()
的变体类型。 调用的参数会传递给 __new__()
,并且在通常情况下,也会传递给 __init__()
来初始化新的实例。
3.2.8.9. 类实例
任意类的实例可以通过在其所属类中定义 __call__()
方法变成可调用对象。
3.2.9. 模块
模块是 Python 代码的基本组织单元,由 导入系统 创建,它或是通过 import
语句,或是通过调用 importlib.import_module()
和内置的 __import__()
等函数来唤起。 模块对象具有通过 字典
对象实现的命名空间(就是被定义在模块中的函数的 __globals__
属性所引用的字典)。 属性引用将被转换为在该字典中的查找操作,例如 m.x
就等价于 m.__dict__["x"]
。 模块对象不包含用于初始化模块的代码对象(因为初始化完成后已不再需要它)。
属性赋值会更新模块的命名空间字典,例如 m.x = 1
等同于 m.__dict__["x"] = 1
。
3.2.9.1. 模块对象上与导入相关的属性
Module objects have the following attributes that relate to the import system. When a module is created using the machinery associated with the import system, these attributes are filled in based on the module's spec, before the loader executes and loads the module.
To create a module dynamically rather than using the import system, it's recommended to use importlib.util.module_from_spec()
, which will set the various import-controlled attributes to appropriate values. It's also possible to use the types.ModuleType
constructor to create modules directly, but this technique is more error-prone, as most attributes must be manually set on the module object after it has been created when using this approach.
小心
With the exception of __name__
, it is strongly recommended that you rely on __spec__
and its attributes instead of any of the other individual attributes listed in this subsection. Note that updating an attribute on __spec__
will not update the corresponding attribute on the module itself:
- >>> import typing
- >>> typing.__name__, typing.__spec__.name
- ('typing', 'typing')
- >>> typing.__spec__.name = 'spelling'
- >>> typing.__name__, typing.__spec__.name
- ('typing', 'spelling')
- >>> typing.__name__ = 'keyboard_smashing'
- >>> typing.__name__, typing.__spec__.name
- ('keyboard_smashing', 'spelling')
- module.name
- 用于在导入系统中唯一地标识模块的名称。 对于直接执行的模块,这将被设为
"__main__"
。
该属性必须被设为模块的完整限定名称。 它应当与 module.__spec__.name
的值相匹配。
- module.spec
- 模块与导入系统相关联的状态的记录。
Set to the module spec
that was used when importing the module. See 模块规格说明 for more details.
Added in version 3.4.
- module.package
- The package a module belongs to.
If the module is top-level (that is, not a part of any specific package) then the attribute should be set to ''
(the empty string). Otherwise, it should be set to the name of the module's package (which can be equal to module.__name__
if the module itself is a package). See PEP 366 [https://peps.python.org/pep-0366/] for further details.
This attribute is used instead of __name__
to calculate explicit relative imports for main modules. It defaults to None
for modules created dynamically using the types.ModuleType
constructor; use importlib.util.module_from_spec()
instead to ensure the attribute is set to a str
.
It is strongly recommended that you use module.__spec__.parent
instead of module.__package__
. __package__
is now only used as a fallback if __spec__.parent
is not set, and this fallback path is deprecated.
在 3.4 版本发生变更: This attribute now defaults to None
for modules created dynamically using the types.ModuleType
constructor. Previously the attribute was optional.
在 3.6 版本发生变更: The value of __package__
is expected to be the same as __spec__.parent
. __package__
is now only used as a fallback during import resolution if __spec__.parent
is not defined.
在 3.10 版本发生变更: ImportWarning
is raised if an import resolution falls back to __package__
instead of __spec__.parent
.
在 3.12 版本发生变更: Raise DeprecationWarning
instead of ImportWarning
when falling back to __package__
during import resolution.
Deprecated since version 3.13, will be removed in version 3.15: __package__
will cease to be set or taken into consideration by the import system or standard library.
- module.loader
- The loader object that the import machinery used to load the module.
This attribute is mostly useful for introspection, but can be used for additional loader-specific functionality, for example getting data associated with a loader.
__loader__
defaults to None
for modules created dynamically using the types.ModuleType
constructor; use importlib.util.module_from_spec()
instead to ensure the attribute is set to a loader object.
It is strongly recommended that you use module.__spec__.loader
instead of module.__loader__
.
在 3.4 版本发生变更: This attribute now defaults to None
for modules created dynamically using the types.ModuleType
constructor. Previously the attribute was optional.
Deprecated since version 3.12, will be removed in version 3.16: Setting __loader__
on a module while failing to set __spec__.loader
is deprecated. In Python 3.16, __loader__
will cease to be set or taken into consideration by the import system or the standard library.
- module.path
- A (possibly empty) sequence of strings enumerating the locations where the package's submodules will be found. Non-package modules should not have a
__path__
attribute. See 模块的 path 属性 for more details.
It is strongly recommended that you use module.__spec__.submodule_search_locations
instead of module.__path__
.
- module.file
- module.cached
__file__
and__cached__
are both optional attributes that may or may not be set. Both attributes should be astr
when they are available.
__file__
indicates the pathname of the file from which the module was loaded (if loaded from a file), or the pathname of the shared library file for extension modules loaded dynamically from a shared library. It might be missing for certain types of modules, such as C modules that are statically linked into the interpreter, and the import system may opt to leave it unset if it has no semantic meaning (for example, a module loaded from a database).
If __file__
is set then the __cached__
attribute might also be set, which is the path to any compiled version of the code (for example, a byte-compiled file). The file does not need to exist to set this attribute; the path can simply point to where the compiled file would exist (see PEP 3147 [https://peps.python.org/pep-3147/]).
Note that __cached__
may be set even if __file__
is not set. However, that scenario is quite atypical. Ultimately, the loader is what makes use of the module spec provided by the finder (from which __file__
and __cached__
are derived). So if a loader can load from a cached module but otherwise does not load from a file, that atypical scenario may be appropriate.
强烈 建议你使用 module.__spec__.cached
来代替 module.__cached__
。
Deprecated since version 3.13, will be removed in version 3.15: 当设置 __spec__.cached
失败时在模块上设置 __cached__
的做法已被弃用。 在 Python 3.15 中,__cached__
将不会再被设置或被导入系统或标准库纳入考虑。
3.2.9.2. 模块对象上的其他可写属性
除了上面列出的导入相关属性,模块对象还具有下列可写属性:
- module.doc
- 模块的文档字符串,或者如果不可用则为
None
。 另请参阅:__doc__ 属性
。
- module.annotations
- 包含在模块体执行期间收集的 变量标注 的字典。 有关使用
__annotations__
的最佳实践,请参阅 注解最佳实践。
3.2.9.3. 模块字典
模块对象还具有以下特殊的只读属性:Module objects also have the following special read-only attribute:
- module.dict
- The module's namespace as a dictionary object. Uniquely among the attributes listed here,
__dict__
cannot be accessed as a global variable from within a module; it can only be accessed as an attribute on module objects.
由于 CPython 清理模块字典的设定,当模块离开作用域时模块字典将会被清理,即使该字典还有活动的引用。想避免此问题,可复制该字典或保持模块状态以直接使用其字典。
3.2.10. 自定义类
自定义类这种类型一般是通过类定义来创建 (参见 类定义 一节)。 每个类都有一个通过字典对象实现的命名空间。 类属性引用会被转化为在此字典中查找,例如,C.x
会被转化为 C.__dict__["x"]
(不过也存在一些钩子对象允许其他定位属性的方式)。 当未在其中找到某个属性名称时,会继续在基类中查找。这种基类搜索使用 C3 方法解析顺序,即使存在 '钻石形' 继承结构既有多条继承路径连到一个共同祖先也能保持正确的行为。 有关 Python 使用的 C3 MRO 的详情可在 Python 2.3 方法解析顺序 查看。
当一个类属性引用 (假设类名为 C
) 会产生一个类方法对象时,它将转化为一个 __self__
属性为 C
的实例方法对象。 当它会产生一个 staticmethod
对象时,它将转换为该静态方法对象所包装的对象。 有关有类的 __dict__
实际包含内容以外获取属性的其他方式请参阅 实现描述器 一节。
类属性赋值会更新类的字典,但不会更新基类的字典。
类对象可被调用 (见上文) 以产生一个类实例 (见下文)。
3.2.10.1. 特殊属性
属性 | 含意 |
---|---|
- type.name - |
类的名称。 另请参阅: __name__ 属性 。
|
- type.qualname - |
类的 qualified name。 另请参阅: __qualname__ 属性 。
|
- type.module - | 类定义所在模块的名称。 |
- type.dict - |
一个提供类的命名空间的只读视图的 映射代理 。 另请参阅: __dict__ 属性 。
|
- type.bases - |
一个包含类的基类的 tuple ,对于定义为 class X(A, B, C) 的类,X.__bases__ 将等于 (A, B, C) 。
|
- type.doc - |
类的文档字符串,如果未定义则为 None 。 不会被子类继承。 if undefined. Not inherited by subclasses.
|
- type.annotations - |
A dictionary containing variable annotations collected during class body execution. For best practices on working with __annotations__ , please see 注解最佳实践.
小心
Accessing the __annotations__ attribute of a class object directly may yield incorrect results in the presence of metaclasses. In addition, the attribute may not exist for some classes. Use inspect.get_annotations() to retrieve class annotations safely.
|
- type.type_params - |
A tuple containing the type parameters of a generic class.
Added in version 3.12.
|
- type.static_attributes - |
A tuple containing names of attributes of this class which are assigned through self.X from any function in its body.
Added in version 3.13.
|
- type.firstlineno - |
The line number of the first line of the class definition, including decorators. Setting the __module__ attribute removes the __firstlineno__ item from the type's dictionary.
Added in version 3.13.
|
- type.mro - |
由在方法解析期间当查找基类时将被纳入考虑的类组成的 tuple 。
|
3.2.10.2. 特殊方法
除了上面介绍的特殊属性,所有的 Python 类还具有以下两个方法:
- type.mro()
- 此方法可由一个元类来重写以便为其实例定制方法解析顺序。 它会在类实例化时被调用,其结果将存储在
__mro__
中。
- type.subclasses()
- 每个类都会保存一个由指向其直接子类的弱引用组成的列表。 此方法将返回一个由所有仍然存在的这种引用组成的列表。 列表项将按定义顺序排列。 例如:
- >>> class A: pass
- >>> class B(A): pass
- >>> A.__subclasses__()
- [<class 'B'>]
3.2.11. 类实例
类实例可通过调用类对象来创建(见上文)。 每个类实例都有通过一个字典对象实现的独立命名空间,属性引用会首先在此字典中进行查找。 当未在其中发现某个属性,而实例对应的类中有该属性时,会继续在类属性中查找。 如果找到的类属性是一个用户自定义函数对象,它会被转化为实例方法对象,其 __self__
属性即该实例。 静态方法和类方法对象也会被转化;参见上文的“类”小节。 要了解其他通过类实例来获取相应类属性的方式请参阅 实现描述器 小节,这样得到的属性可能与实际存放在类的 __dict__
中的对象不同。 如果未找到类属性,而对象所属的类具有 __getattr__()
方法,则会调用该方法来满足查找要求。
属性赋值和删除会更新实例的字典,但绝不会更新类的字典。 如果类具有 __setattr__()
或 __delattr__()
方法,则将调用该方法而不再直接更新实例的字典。
如果类实例具有某些特殊名称的方法,就可以伪装为数字、序列或映射。参见 特殊方法名称 一节。
3.2.11.1. 特殊属性
- object.class
- 类实例所属的类。
- object.dict
- 一个用于存储对象的(可写)属性的字典或其他映射对象。 并非所有实例都具有
__dict__
属性;请参阅 slots 章节了解详情。
3.2.12. I/O 对象 (或称文件对象)
file object 表示一个打开的文件。有多种快捷方式可用来创建文件对象: open()
内置函数,以及 os.popen()
, os.fdopen()
和 socket 对象的 makefile()
方法 (还可能使用某些扩展模块所提供的其他函数或方法)。
sys.stdin
, sys.stdout
和 sys.stderr
会初始化为对应于解释器标准输入、输出和错误流的文件对象;它们都会以文本模式打开,因此都遵循 io.TextIOBase
抽象类所定义的接口。
3.2.13. 内部类型
某些由解释器内部使用的类型也被暴露给用户。它们的定义可能随未来解释器版本的更新而变化,为内容完整起见在此处一并介绍。
3.2.13.1. 代码对象
代码对象表示 编译为字节的 可执行 Python 代码,或称 bytecode。代码对象和函数对象的区别在于函数对象包含对函数全局对象 (函数所属的模块) 的显式引用,而代码对象不包含上下文;而且默认参数值会存放于函数对象而不是代码对象内 (因为它们表示在运行时算出的值)。与函数对象不同,代码对象不可变,也不包含对可变对象的引用 (不论是直接还是间接)。