On this page
3. Data model
3.1. 对象,值和类型
对象是 Python 的数据抽象。 Python 程序中的所有数据都由对象或对象之间的关系表示。 (在某种意义上,并且按照冯·诺依曼的“存储程序计算机”模型,代码也由对象表示.)
每个对象都有一个标识,一个类型和一个值。创建对象后,其“身份”就永远不会改变;您可能会认为它是对象在内存中的地址。 'is'运算符比较两个对象的身份; id()函数返回一个表示其身份的整数。
CPython 实现细节: 对于 CPython,id(x)
是存储x
的内存地址。
对象的类型确定对象支持的操作(例如,“它是否有长度?”),并且还定义了该类型对象的可能值。 type()函数返回对象的类型(对象本身)。像其身份一样,对象的* type *也不可更改。 [1]
某些对象的值可以更改。其值可以更改的对象被称为* mutable ;创建后其值不可更改的对象称为 immutable *。 (当更改可变对象的值时,包含对可变对象的引用的不可变容器对象的值可以更改;但是该容器仍被认为是不可变的,因为它所包含的对象的集合无法更改.因此,不可变性并不是严格意义上的与具有不变的值一样,它更加微妙.)对象的可变性由其类型决定;例如,数字,字符串和 Tuples 是不可变的,而字典和列表则是可变的。
从不显式销毁对象。但是,当它们变得不可访问时,它们可能会被垃圾回收。允许某个实现推迟或完全取消垃圾回收-只要没有收集到仍可到达的对象,垃圾回收的实现方式就取决于实现质量。
CPython 实现细节: CPython 当前使用带有循环计数垃圾的(可选)延迟检测的引用计数方案,该方案会在无法访问时立即收集大多数对象,但不能保证收集包含循环引用的垃圾。有关控制循环垃圾收集的信息,请参见gc模块的文档。其他实现的行为有所不同,CPython 可能会发生变化。当对象变得不可访问时,不要依赖它们的立即完成(因此,您应始终明确关闭文件)。
请注意,使用实现的跟踪或调试Function可能会使通常可以收集的对象保持活动状态。另请注意,使用'try…except'语句捕获异常可能会使对象保持活动状态。
一些对象包含对“外部”资源的引用,例如打开的文件或窗口。可以理解,在垃圾回收对象时释放了这些资源,但是由于不能保证垃圾回收的发生,因此此类对象还提供了一种释放外部资源的显式方式,通常是close()
方法。强烈建议使用程序显式关闭此类对象。 'try…finally'语句和'with'语句提供了方便的方法。
一些对象包含对其他对象的引用。这些被称为容器。容器的示例是 Tuples,列表和字典。引用是容器值的一部分。在大多数情况下,当我们谈论容器的值时,我们暗含的是值,而不是所包含对象的标识。但是,当我们谈论容器的可变性时,仅隐含了直接包含的对象的身份。因此,如果不可变容器(如 Tuples)包含对可变对象的引用,则当该可变对象更改时,其值也会更改。
类型影响对象行为的几乎所有方面。甚至对象标识的重要性在某种意义上也受到影响:对于不可变类型,计算新值的操作实际上可能返回对具有相同类型和值的任何现有对象的引用,而对于可变对象,则不允许这样做。例如,根据实现的不同,在a = 1; b = 1
,a
和b
之后可能会或可能不会使用值 1 引用相同的对象,但是在c = []; d = []
之后,c
和d
被保证引用了两个不同的,唯一的,新创建的空列表。 (请注意c = d = []
将相同的对象分配给c
和d
.)
3.2. 标准类型层次结构
以下是 Python 内置的类型的列表。扩展模块(使用 C,Java 或其他语言编写,取决于实现)可以定义其他类型。Future 的 Python 版本可能会在类型层次结构中添加类型(例如,有理数,有效存储的整数数组等),尽管通常会pass标准库提供此类添加。
下面的某些类型描述包含一个列出“特殊属性”的段落。这些是提供对实现的访问的属性,并不旨在用于一般用途。他们的定义将来可能会改变。
None
- 此类型具有单个值。有一个具有此值的对象。pass内置名称
None
访问此对象。它用于表示在许多情况下不存在值,例如,它是从未显式返回任何内容的函数中返回的。其真实值是错误的。
- 此类型具有单个值。有一个具有此值的对象。pass内置名称
NotImplemented
- 此类型具有单个值。有一个具有此值的对象。pass内置名称
NotImplemented
访问此对象。如果数字方法和丰富比较方法未实现所提供操作数的操作,则应返回此值。 (然后,解释程序将根据操作员try执行反射操作或其他回退.)其真实值是 true。
- 此类型具有单个值。有一个具有此值的对象。pass内置名称
有关更多详细信息,请参见实施算术运算。
Ellipsis
- 此类型具有单个值。有一个具有此值的对象。pass Literals
...
或内置名称Ellipsis
访问该对象。它的真实价值是真实的。
- 此类型具有单个值。有一个具有此值的对象。pass Literals
-
- 它们由数字 Literals 创建,并由算术运算符和算术内置函数作为结果返回。数字对象是不可变的。一旦 Creating 了价值,就永远不会改变。 Python 数字当然与 math 数字密切相关,但受到计算机中数字表示形式的限制。
Python 区分整数,浮点数和复数:
-
- 这些代表整数 math 集合(正数和负数)中的元素。
整数有两种类型:
Integers (int)
Note
这些代表无限范围内的数字,仅受可用(虚拟)内存的限制。为了进行移位和掩码运算,假定采用二进制表示,并在 2 的补码变体中表示负数,从而给出了无限的符号位字符串向左延伸的错觉。
布尔值(bool)
- These represent the truth values False and True\. The two objects representing the values `False` and `True` are the only Boolean objects\. The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings `"False"` or `"True"` are returned, respectively\.
整数表示规则旨在对涉及负整数的移位和掩码运算提供最有意义的解释。
-
- 这些代表机器级别的双精度浮点数。您只能接受底层计算机体系结构(以及 C 或 Java 实现)的接受范围和溢出处理。 Python 不支持单精度浮点数;节省处理器和内存使用量(通常是使用它们的原因)与在 Python 中使用对象的开销相形见,,因此没有理由使该语言复杂化为两种浮点数。
-
- 这些将复数表示为Pair机器级双精度浮点数。浮点数的注意事项相同。可以pass只读属性
z.real
和z.imag
检索复数z
的实部和虚部。
- 这些将复数表示为Pair机器级双精度浮点数。浮点数的注意事项相同。可以pass只读属性
Sequences
- 这些代表由非负数索引的有限有序集。内置函数len()返回序列的项数。当序列的长度为* n 时,索引集包含数字 0、1,…, n * -1.序列* a 的项目 i *由
a[i]
选择。
- 这些代表由非负数索引的有限有序集。内置函数len()返回序列的项数。当序列的长度为* n 时,索引集包含数字 0、1,…, n * -1.序列* a 的项目 i *由
序列还支持切片:a[i:j]
选择索引为* k 的所有项目,使得 i * <=
* k * <
* j *。当用作表达式时,切片是相同类型的序列。这意味着对索引集进行了重新编号,使其从 0 开始。
一些序列还支持带有第三个“ step”参数的“扩展切片”:a[i:j:k]
选择索引为* x 的 a 的所有项,其中x = i + n*k
, n * >=
0
和* i * <=
* x * <
* j *。
序列根据其可变性进行区分:
Immutable sequences
- 不变序列类型的对象一旦创建就无法更改。 (如果对象包含对其他对象的引用,则这些其他对象可能是可变的,并且可能会更改;但是,不可变对象直接引用的对象的集合不能更改.)
以下类型是不可变序列:
Strings
- A string is a sequence of values that represent Unicode code points\. All the code points in the range `U+0000 - U+10FFFF` can be represented in a string\. Python doesn't have a `char` type; instead, every code point in the string is represented as a string object with length `1` \. The built\-in function [ord\(\)](library-functions.html#ord) converts a code point from its string form to an integer in the range `0 - 10FFFF` ; [chr\(\)](library-functions.html#chr) converts an integer in the range `0 - 10FFFF` to the corresponding length `1` string object\. [str\.encode\(\)](library-stdtypes.html#str.encode) can be used to convert a [str](library-stdtypes.html#str) to [bytes](library-stdtypes.html#bytes) using the given text encoding, and [bytes\.decode\(\)](library-stdtypes.html#bytes.decode) can be used to achieve the opposite\.
- Tuples
- The items of a tuple are arbitrary Python objects\. Tuples of two or more items are formed by comma\-separated lists of expressions\. A tuple of one item \(a 'singleton'\) can be formed by affixing a comma to an expression \(an expression by itself does not create a tuple, since parentheses must be usable for grouping of expressions\)\. An empty tuple can be formed by an empty pair of parentheses\.
- Bytes
- A bytes object is an immutable array\. The items are 8\-bit bytes, represented by integers in the range 0 \<= x \< 256\. Bytes literals \(like `b'abc'` \) and the built\-in [bytes\(\)](library-stdtypes.html#bytes) constructor can be used to create bytes objects\. Also, bytes objects can be decoded to strings via the [decode\(\)](library-stdtypes.html#bytes.decode) method\.
Mutable sequences
- 创建可变序列后,可以对其进行更改。订阅和切片符号可以用作分配和del(删除)语句的目标。
当前有两种固有的可变序列类型:
Lists
- The items of a list are arbitrary Python objects\. Lists are formed by placing a comma\-separated list of expressions in square brackets\. \(Note that there are no special cases needed to form lists of length 0 or 1\.\)
- Byte Arrays
- A bytearray object is a mutable array\. They are created by the built\-in [bytearray\(\)](library-stdtypes.html#bytearray) constructor\. Aside from being mutable \(and hence unhashable\), byte arrays otherwise provide the same interface and functionality as immutable [bytes](library-stdtypes.html#bytes) objects\.
扩展模块array和collections模块一样,提供了可变序列类型的其他示例。
Set types
- 这些代表无序,有限的唯一不变对象集。因此,它们不能由任何下标索引。但是,可以对其进行迭代,并且内置函数len()返回集合中的项目数。集的常见用途是快速成员资格测试,从序列中删除重复项以及计算 math 运算(例如交集,并集,差和对称差)。
对于集合元素,相同的不变性规则适用于字典键。请注意,数字类型遵循数字比较的一般规则:如果两个数字比较相等(例如1
和1.0
),则集合中只能包含其中一个。
当前有两种内部集类型:
Sets
- 这些代表可变的集合。它们是由内置的set()构造函数创建的,之后可以pass多种方法(例如
add()
)进行修改。
- 这些代表可变的集合。它们是由内置的set()构造函数创建的,之后可以pass多种方法(例如
Frozen sets
- 这些代表一个不变的集合。它们由内置的frozenset()构造函数创建。由于冻结集是不可变的且是hashable,因此它可以再次用作另一个集的元素或用作字典键。
Mappings
当前只有一种内部 Map 类型:
Dictionaries
- 这些代表由几乎任意值索引的有限对象集。唯一不可接受作为键的值类型是包含列表或字典或其他可变类型的值,这些值或值是按值而不是对象标识进行比较的,原因是字典的有效实现需要键的哈希值保持不变。用于键的数字类型遵循数字比较的一般规则:如果两个数字比较相等(例如
1
和1.0
),则可以互换使用它们来索引相同的字典条目。
- 这些代表由几乎任意值索引的有限对象集。唯一不可接受作为键的值类型是包含列表或字典或其他可变类型的值,这些值或值是按值而不是对象标识进行比较的,原因是字典的有效实现需要键的哈希值保持不变。用于键的数字类型遵循数字比较的一般规则:如果两个数字比较相等(例如
字典保留插入 Sequences,这意味着将按照在字典上 Sequences 添加键的 Sequences 生成键。替换现有密钥不会改变 Sequences,但是删除密钥并重新插入会将其添加到末尾,而不是保留其旧位置。
字典是可变的;可以使用{...}
表示法创建它们(请参见Dictionary displays部分)。
扩展模块dbm.ndbm和dbm.gnu与collections模块一样,提供了 Map 类型的其他示例。
在 3.7 版中进行了更改:在 3.6 之前的 Python 版本中,词典未保留插入 Sequences。在 CPython 3.6 中,保留了插入 Sequences,但当时它被视为实现细节,而不是语言保证。
Callable types
- 这些是可以应用函数调用操作的类型(请参见Calls):
User-defined functions
- 用户定义的Function对象由Function定义创建(请参见Function definitions)。应该使用包含与函数的形式参数列表相同数量的项的参数列表来调用它。
Special attributes:
Attribute | Meaning | |
---|---|---|
__doc__ |
该函数的文档字符串,或None (如果不可用);不是子类继承的。 |
Writable |
name | 函数的名称。 | Writable |
qualname | 该函数的qualified name。 | |
3.3 版中的新增Function。 |
可写 | |
__module__ |
定义函数的模块名称,或None (如果不可用)。 |
可写 |
__defaults__ |
包含具有默认值的参数的默认参数值的 Tuples,或者None (如果没有参数具有默认值)。 |
|
__code__ |
表示已编译函数主体的代码对象。 | 可写 |
__globals__ |
对字典的引用,该字典包含函数的全局变量—定义函数的模块的全局命名空间。 | 只读 |
dict | 支持任意函数属性的名称空间。 | 可写 |
__closure__ |
None 或包含该函数的自由变量绑定的单元格 Tuples。有关cell_contents 属性的信息,请参见下文。 |
只读 |
__annotations__ |
包含参数 Comments 的字典。字典的键是参数名称,如果返回的话,则用'return' 表示返回 Comments。 |
|
__kwdefaults__ |
包含仅关键字参数默认值的字典。 | 可写 |
标记为“可写”的大多数属性都会检查分配值的类型。
函数对象还支持获取和设置任意属性,这些属性可以用于例如将元数据附加到函数。常规属性点符号用于获取和设置此类属性。 请注意,当前实现仅支持用户定义函数上的函数属性。将来可能会支持内置函数的函数属性.
单元格对象的属性为cell_contents
。这可用于获取单元格的值以及设置值。
可以从其代码对象中检索有关函数定义的其他信息。请参阅下面的内部类型说明。 cell类型可以在types模块中访问。
Instance methods
- 实例方法对象结合了一个类,一个类实例和任何可调用对象(通常是用户定义的函数)。
特殊的只读属性:__self__
是类实例对象,__func__
是函数对象; __doc__
是方法的文档(与__func__.__doc__
相同); name是方法名称(与__func__.__name__
相同); __module__
是在其中定义方法的模块的名称,或None
(如果不可用)。
方法还支持访问(但不设置)基础函数对象上的任意函数属性。
如果某个类的属性是用户定义的函数对象或类方法对象,则在获取类的属性时(可能pass该类的实例)可以创建用户定义的方法对象。
当pass某个类的实例之一从类中检索用户定义的函数对象来创建实例方法对象时,其__self__
属性就是该实例,并且该方法对象被称为已绑定。新方法的__func__
属性是原始函数对象。
pass从类或实例中检索类方法对象来创建实例方法对象时,其__self__
属性是该类本身,而其__func__
属性是该类方法的基础函数对象。
调用实例方法对象时,将调用基础函数(__func__
),并将类实例(__self__
)插入参数列表的前面。例如,当C
是包含函数f()
的定义的类,并且x
是C
的实例时,调用x.f(1)
等效于调用C.f(x, 1)
。
当从类方法对象派生实例方法对象时,存储在__self__
中的“类实例”实际上将是类本身,因此调用x.f(1)
或C.f(1)
等效于调用f(C,1)
,其中f
是基础函数。
请注意,每次从实例检索属性时,都会发生从函数对象到实例方法对象的转换。在某些情况下,卓有成效的优化是将属性分配给局部变量并调用该局部变量。还要注意,这种转换仅发生在用户定义的函数上。其他可调用对象(以及所有不可调用对象)无需进行转换即可检索。同样重要的是要注意,作为类实例属性的用户定义函数不会转换为绑定方法。 仅发生在函数是类的属性时。
Generator functions
- 使用yield语句(请参阅yield语句)的函数或方法称为生成器函数。调用此函数时,始终会返回一个迭代器对象,该对象可用于执行函数的主体:调用迭代器的iterator.next()方法将使该函数执行,直到使用
yield
语句提供值为止。当函数执行return语句或结束结尾时,将引发StopIteration异常,并且迭代器将到达要返回的值集的结尾。
- 使用yield语句(请参阅yield语句)的函数或方法称为生成器函数。调用此函数时,始终会返回一个迭代器对象,该对象可用于执行函数的主体:调用迭代器的iterator.next()方法将使该函数执行,直到使用
Coroutine functions
- 使用async def定义的函数或方法称为协程函数。调用此函数时,将返回coroutine对象。它可能包含await表达式以及async with和async for语句。另请参见Coroutine Objects部分。
异步 Generator Function
调用异步迭代器的aiterator.__anext__()
方法将返回awaitable,它将在 await 时执行,直到使用yield表达式提供值为止。当函数执行空的return语句或结束结尾时,将引发StopAsyncIteration异常,并且异步迭代器将到达要产生的值集的末尾。
Built-in functions
- 内置函数对象是 C 函数的包装器。内置函数的示例是len()和math.sin()(math是标准的内置模块)。参数的数量和类型由 C 函数确定。特殊的只读属性:
__doc__
是函数的文档字符串,或None
(如果不可用); name是函数的名称;__self__
设置为None
(但请参见下一项);__module__
是定义Function的模块的名称,或None
(如果不可用)。
- 内置函数对象是 C 函数的包装器。内置函数的示例是len()和math.sin()(math是标准的内置模块)。参数的数量和类型由 C 函数确定。特殊的只读属性:
Built-in methods
- 这实际上是内置函数的另一种伪装,这次包含一个作为隐式额外参数传递给 C 函数的对象。内置方法的一个示例是
alist.append()
,假设* alist 是列表对象。在这种情况下,特殊的只读属性__self__
被设置为 alist *表示的对象。
- 这实际上是内置函数的另一种伪装,这次包含一个作为隐式额外参数传递给 C 函数的对象。内置方法的一个示例是
Classes
Class Instances
- pass在类中定义call()方法,可以使任意类的实例可调用。
Modules
- 模块是 Python 代码的基本组织单位,由import语句调用的import system或调用importlib.import_module()和内置import()之类的函数来创建。模块对象具有由字典对象实现的名称空间(这是由模块中定义的函数的
__globals__
属性引用的字典)。将属性引用转换为此字典中的查找,例如m.x
等效于m.__dict__["x"]
。模块对象不包含用于初始化模块的代码对象(因为一旦完成初始化就不需要它)。
- 模块是 Python 代码的基本组织单位,由import语句调用的import system或调用importlib.import_module()和内置import()之类的函数来创建。模块对象具有由字典对象实现的名称空间(这是由模块中定义的函数的
属性分配会更新模块的名称空间字典,例如m.x = 1
等效于m.__dict__["x"] = 1
。
sched 义(可写)属性:name是模块的名称; __doc__
是模块的文档字符串,或None
(如果不可用); __annotations__
(可选)是包含在模块主体执行期间收集的variable annotations的字典; file是从中加载模块的文件的路径名(如果它是从文件加载的)。某些类型的模块(例如静态链接到解释器的 C 模块)可能缺少file属性。对于从共享库动态加载的扩展模块,它是共享库文件的路径名。
特殊的只读属性:dict是作为字典对象的模块的命名空间。
CPython 实现细节: 由于 CPython 清除模块词典的方式,即使模块仍具有实时引用,当模块超出范围时,模块词典也会被清除。为避免这种情况,请复制字典或在直接使用其字典时保留模块。
Custom classes
- 自定义类类型通常由类定义创建(请参阅Class definitions)。类具有由字典对象实现的名称空间。将类属性引用转换为此字典中的查找,例如,
C.x
转换为C.__dict__["x"]
(尽管有许多允许使用其他方法定位属性的钩子)。当在此处找不到属性名称时,将 continue 在 Base Class 中搜索属性。这种对 Base Class 的搜索使用 C3 方法解析 Sequences,即使在存在“钻石”继承结构的情况下,该 Sequences 也能正确运行,在“钻石”继承结构中,存在多个返回到共同祖先的继承路径。有关 Python 使用的 C3 MRO 的其他详细信息,可以在https://www.python.org/download/releases/2.3/mro/附带的 2.3 版本附带的文档中找到。
- 自定义类类型通常由类定义创建(请参阅Class definitions)。类具有由字典对象实现的名称空间。将类属性引用转换为此字典中的查找,例如,
当类属性引用(例如C
类)产生一个类方法对象时,它将转换为__self__
属性为C
的实例方法对象。当产生静态方法对象时,它将转换为由静态方法对象包装的对象。有关从类检索的属性可能与实际包含在其dict中的属性不同的另一种方式,请参见Implementing Descriptors部分。
类属性分配更新类的字典,而不更新 Base Class 的字典。
可以调用一个类对象(请参见上文)以产生一个类实例(请参见下文)。
特殊属性:name是类名; __module__
是定义类的模块名称; dict是包含类名称空间的字典; bases是包含 Base Class 的 Tuples,按 Base Class 在 Base Class 列表中的出现 Sequences 排列; __doc__
是该类的文档字符串,或者None
(如果未定义); __annotations__
(可选)是包含在类主体执行期间收集的variable annotations的字典。
Class instances
- pass调用类对象来创建类实例(请参见上文)。一个类实例具有一个实现为字典的名称空间,这是搜索属性引用的第一位。如果在该处找不到属性,并且实例的类具有该名称的属性,则 continue 使用类属性进行搜索。如果发现类属性是用户定义的函数对象,则将其转换为实例方法对象,该对象的对象
__self__
属性为实例。静态方法和类方法对象也将转换。请参见上文“类别”下的内容。有关pass其实例检索的类的属性可能与实际存储在该类dict中的对象不同的另一种方式,请参见Implementing Descriptors部分。如果未找到 class 属性,并且对象的类具有getattr()方法,则调用该方法以满足查找。
- pass调用类对象来创建类实例(请参见上文)。一个类实例具有一个实现为字典的名称空间,这是搜索属性引用的第一位。如果在该处找不到属性,并且实例的类具有该名称的属性,则 continue 使用类属性进行搜索。如果发现类属性是用户定义的函数对象,则将其转换为实例方法对象,该对象的对象
属性分配和删除将更新实例的字典,而不会更新类的字典。如果该类具有setattr()或delattr()方法,则将调用此方法,而不是直接更新实例字典。
如果类实例具有使用某些特殊名称的方法,则它们可以 Feign 为数字,序列或 Map。参见特殊方法名称部分。
I/O 对象(也称为文件对象)
- file object代表打开的文件。可以使用各种快捷方式来创建文件对象:open()内置函数,以及套接字对象的os.popen(),os.fdopen()和makefile()方法(可能还有其他Function或扩展模块提供的方法)。
对象sys.stdin
,sys.stdout
和sys.stderr
被初始化为与解释器的标准 Importing,输出和错误流相对应的文件对象。它们都以文本模式打开,因此遵循io.TextIOBase抽象类定义的界面。
Internal types
- 解释器内部使用的一些类型向用户公开。它们的定义可能会随将来版本的解释器而变化,但是为了完整起见在此提及它们。
Code objects
- 代码对象表示字节编译的可执行 Python 代码或bytecode。代码对象和Function对象之间的区别在于,Function对象包含对函数全局变量(定义该模块的模块)的显式引用,而代码对象则不包含上下文。默认参数值也存储在函数对象中,而不存储在代码对象中(因为它们表示运行时计算出的值)。与函数对象不同,代码对象是不可变的,并且不包含(直接或间接)可变对象的引用。
特殊的只读属性:co_name
给出函数名称; co_argcount
是位置参数的总数(包括仅位置参数和具有默认值的参数); co_posonlyargcount
是仅位置参数(包括具有默认值的参数)的数量; co_kwonlyargcount
是仅关键字参数(包括具有默认值的参数)的数量; co_nlocals
是函数使用的局部变量数(包括参数); co_varnames
是一个包含局部变量名称的 Tuples(以参数名称开头); co_cellvars
是一个 Tuples,其中包含嵌套函数引用的局部变量的名称; co_freevars
是一个包含自由变量名称的 Tuples; co_code
是代表字节码指令序列的字符串; co_consts
是一个 Tuples,包含字节码使用的 Literals; co_names
是一个 Tuples,包含字节码使用的名称; co_filename
是用于编译代码的文件名; co_firstlineno
是函数的第一行号; co_lnotab
是编码从字节码偏移量到行号的 Map 的字符串(有关详细信息,请参见解释器的源代码); co_stacksize
是所需的堆栈大小; co_flags
是对解释器的许多标志进行编码的整数。
为co_flags
定义了以下标志位:如果函数使用*arguments
语法接受任意数量的位置参数,则设置位0x04
;如果函数使用**keywords
语法接受任意关键字参数,则设置位0x08
;如果函数是生成器,则设置位0x20
。
将来的Function语句(from __future__ import division
)也使用co_flags
中的位来指示是否在启用了特定Function的情况下编译了代码对象:如果Function在启用了 Future 除法的情况下进行编译,则位0x2000
设置;否则,早期版本的 Python 中使用了0x10
和0x1000
位。
co_flags
中的其他位保留供内部使用。
如果代码对象表示函数,则co_consts
中的第一项是函数的文档字符串,或者None
(如果未定义)。
Frame objects
- 框架对象代表执行框架。它们可能出现在回溯对象中(见下文),并且还传递给已注册的跟踪函数。
特殊的只读属性:f_back
指向上一个堆栈帧(面向调用方),或者None
(如果这是底部堆栈帧); f_code
是在此框架中执行的代码对象; f_locals
是用于查找局部变量的字典; f_globals
用于全局变量; f_builtins
用于内置(内部)名称; f_lasti
给出精确的指令(这是代码对象的字节码字符串的索引)。
特殊的可写属性:f_trace
(如果不是None
)是一个在代码执行期间针对各种事件调用的函数(调试器使用)。通常,每个新的源代码行都会触发一个事件-可以pass将f_trace_lines
设置为False来禁用该事件。
某些实现可能pass将f_trace_opcodes
设置为True来请求按操作码事件。请注意,如果跟踪函数引发的异常逃逸到正在跟踪的函数,则可能导致未定义的解释器行为。
f_lineno
是该帧的当前行号-从跟踪函数中写入该行号将跳至给定的行(仅适用于最底部的帧)。调试器可以pass写入 f_lineno 来实现 Jump 命令(也称为 Set Next 语句)。
框架对象支持一种方法:
frame.
clear
()
-此方法清除对框架保存的局部变量的所有引用。同样,如果帧属于生成器,则生成器将finally确定。这有助于 break 涉及框架对象的参考周期(例如,在捕获异常并存储其 traceback 以供以后使用时)。
如果框架当前正在执行,则RuntimeError引发。
3.4 版的新Function。
Traceback objects
- traceback 对象表示异常的堆栈跟踪。发生异常时会隐式创建一个 traceback 对象,也可以pass调用types.TracebackType显式创建一个 traceback 对象。
对于隐式创建的回溯,当搜索异常处理程序展开执行堆栈时,在每个展开级别上,都会在当前回溯的前面插入一个回溯对象。Importing 异常处理程序后,堆栈跟踪可用于程序。 (请参见try 语句部分。)它可以作为sys.exc_info()
返回的 Tuples 的第三项以及所捕获的异常的__traceback__
属性进行访问。
当程序不包含合适的处理程序时,堆栈跟踪将被写入(格式正确)到标准错误流中。如果解释器是交互式的,则也以sys.last_traceback
的形式提供给用户。
对于显式创建的回溯,由回溯的创建者确定应如何链接tb_next
属性以形成完整的堆栈跟踪。
特殊的只读属性:tb_frame
指向当前级别的执行框架; tb_lineno
给出发生异常的行号; tb_lasti
表示精确指令。如果异常发生在try语句中,没有匹配的 except 子句或带有 finally 子句,则回溯中的行号和最后一条指令可能与其框架对象的行号不同。
特殊的可写属性:tb_next
是堆栈跟踪中的下一层(朝向发生异常的帧),或None
(如果没有下一层)。
在 3.7 版中进行了更改:现在可以从 Python 代码显式实例化 Traceback 对象,并且可以更新现有实例的tb_next
属性。
特殊的只读属性:start
是下限; stop
是上限; step
是步长值;如果Ellipsis,则每个为None
。这些属性可以具有任何类型。
切片对象支持一种方法:
slice.
indices
(* self , length )
-此方法采用单个整数参数 length ,并计算有关切片对象(如果应用于 length 项目序列)将描述的切片信息。它返回三个整数的 Tuples。它们分别是 start 和 stop 索引以及切片的 step *或步幅。丢失或越界索引的处理方式与常规切片一致。静态方法对象
- 静态方法对象提供了一种克服Function对象向上述方法对象的转换的方法。静态方法对象是任何其他对象(通常是用户定义的方法对象)的包装。从类或类实例中检索静态方法对象时,实际返回的对象是包装的对象,无需进行任何进一步的转换。静态方法对象本身不是可调用的,尽管它们通常包装的对象是可调用的。静态方法对象由内置的staticmethod()构造函数创建。
类方法对象
- 类方法对象就像静态方法对象一样,是另一个对象的包装,它更改了从类和类实例检索该对象的方式。上面在“用户定义的方法”下描述了此类检索时类方法对象的行为。类方法对象是由内置的classmethod()构造函数创建的。
3.3. 特殊方法名称
一个类可以pass定义具有特殊名称的方法,来实现由特殊语法调用的某些操作(例如算术运算或下标和切片)。这是 Python 的运算符重载的方法,允许类针对语言运算符定义自己的行为。例如,如果一个类定义了一个名为getitem()的方法,而x
是该类的实例,则x[i]
大致等效于type(x).__getitem__(x, i)
。除非另有说明,否则当未定义适当的方法(通常为AttributeError或TypeError)时,try执行操作会引发异常。
将特殊方法设置为None
表示相应的操作不可用。例如,如果一个类将iter()设置为None
,则该类是不可迭代的,因此在其实例上调用iter()将引发TypeError(而不会退回到getitem())。 [2]
当实现模拟任何内置类型的类时,重要的是,仅在对要建模的对象有意义的程度上实现模拟。例如,某些序列可能适用于单个元素的检索,但是提取切片可能没有意义。 (一个示例是 W3C 的文档对象模型中的NodeList
接口.)
3.3.1. 基本定制
object.
__new__
(* cls * [,* ... *])
典型实现pass使用带有适当参数的super().__new__(cls[, ...])
调用超类的new()方法来创建类的新实例,然后在返回之前根据需要修改新创建的实例。
如果在对象构造期间调用new()并返回* cls 的实例或子类,则将像__init__(self[, ...])
一样调用新实例的init()方法,其中 self *是新实例,其余参数与传递给的参数相同。对象构造函数。
如果new()不返回* cls *实例,则将不会调用新实例的init()方法。
new()主要用于允许不可变类型(例如 int,str 或 tuple)的子类自定义实例创建。为了自定义类的创建,通常也将其覆盖在自定义元类中。
object.
__init__
(* self * [,* ... *])
因为new()和init()在构造对象时一起工作(使用new()创建它,用init()对其进行自定义),所以init()不会返回任何非None
的值;这样做将导致在运行时引发TypeError。
object.
__del__
(* self *)
del()方法有可能(尽管不建议使用!)pass创建对实例的新引用来推迟实例的销毁。这称为对象复活。当即将复活的对象即将被销毁时,是否再次调用del()取决于实现方式。当前的CPython实现仅调用一次。
不能保证在解释器退出时仍然为存在的对象调用del()方法。
Note
del x
不会直接调用x.__del__()
-前者将x
的引用计数减一,而后者仅在x
的引用计数达到零时才调用。
CPython 实现细节: 引用循环有可能防止对象的引用计数变为零。在这种情况下,该周期将稍后被循环垃圾收集器检测并删除。引用循环的常见原因是局部变量中捕获了异常。然后,框架的本地变量引用该异常,该异常引用其自身的回溯,该异常引用引用回溯中捕获的所有帧的局部变量。
See also
gc模块的文档。
Warning
由于调用del()方法的情况不稳定,在执行过程中发生的异常将被忽略,并向sys.stderr
打印警告。特别是:
object.
__repr__
(* self *)
这通常用于调试,因此重要的是,表示形式必须信息丰富且明确。
object.
__str__
(* self *)- 由str(object)和内置函数format()和print()调用,以计算对象的“非正式”或可很好打印的字符串表示形式。返回值必须是string对象。
此方法与object.repr()的不同之处在于,不期望str()返回有效的 Python 表达式:可以使用更方便或更简洁的表示形式。
内置类型object定义的默认实现调用object.repr()。
object.
__format__
(* self , format_spec *)- 由format()内置函数调用,并pass扩展对格式化的字符串 Literals和str.format()方法求值,以生成对象的“格式化”字符串表示形式。 * format_spec *参数是一个字符串,其中包含所需格式化选项的描述。 * format_spec *参数的解释取决于实现format()的类型,但是大多数类要么将格式委托给内置类型之一,要么使用类似的格式选项语法。
有关标准格式语法的说明,请参见格式规格迷你语言。
返回值必须是一个字符串对象。
在版本 3.4 中进行了更改:如果传递了任何非空字符串,则object
的__format_方法本身将引发TypeError。
在版本 3.7 中更改:object.__format__(x, '')
现在等效于str(x)
而不是format(str(self), '')
。
object.
__lt__
(* self , other *)object.
__le__
(* self , other *)object.
__eq__
(* self , other *)object.
__ne__
(* self , other *)object.
__gt__
(* self , other *)object.
__ge__
(* self , other *)- 这些就是所谓的“丰富比较”方法。运算符和方法名称之间的对应关系如下:
x<y
调用x.__lt__(y)
,x<=y
调用x.__le__(y)
,x==y
调用x.__eq__(y)
,x!=y
调用x.__ne__(y)
,x>y
调用x.__gt__(y)
和x>=y
调用x.__ge__(y)
。
- 这些就是所谓的“丰富比较”方法。运算符和方法名称之间的对应关系如下:
如果丰富的比较方法未实现给定参数对的操作,则可能返回单例NotImplemented
。按照惯例,返回False
和True
以进行成功比较。但是,这些方法可以返回任何值,因此,如果在布尔上下文中使用比较运算符(例如,在if
语句的条件下),Python 将在该值上调用bool()以确定结果是 true 还是 false。
默认情况下,ne()委派给eq()并反转结果,除非它是NotImplemented
。比较运算符之间没有其他隐含关系,例如(x<y or x==y)
的 Truth 并不意味着x<=y
。要从单个 root 操作自动生成排序操作,请参见functools.total_ordering()。
有关创建hashable对象的一些重要说明,请参见hash()上的段落,这些对象支持自定义比较操作并可用作字典键。
这些方法没有交换参数版本(当左参数不支持该操作但右参数支持该操作时使用); lt()和gt()是彼此的反射,le()和ge()是彼此的反射,而eq()和ne()是它们自己的反射。如果操作数是不同类型的,并且右操作数的类型是左操作数类型的直接或间接子类,则右操作数的反射方法具有优先级,否则左操作数的方法具有优先级。不考虑虚拟子类化。
object.
__hash__
(* self *)
def __hash__(self):
return hash((self.name, self.nick, self.color))
Note
如果一个类没有定义eq()方法,那么它也不应该定义hash()操作。如果它定义eq()而不是hash(),则其实例将不能用作可散列集合中的项目。如果一个类定义了可变对象并实现了eq()方法,则不应实现hash(),因为可哈希集合的实现要求键的哈希值是不可变的(如果对象的哈希值发生更改,则它将位于错误的哈希存储桶中)。
用户定义的类默认情况下具有eq()和hash()方法。使用它们,所有对象比较不相等(除了它们本身),并且x.__hash__()
返回适当的值,以使x == y
暗示x is y
和hash(x) == hash(y)
。
覆盖eq()并且未定义hash()的类会将其hash()隐式设置为None
。当类的hash()方法为None
时,当程序try检索其哈希值时,该类的实例将引发适当的TypeError,并且在检查isinstance(obj, collections.abc.Hashable)
时也将被正确标识为不可哈希。
如果重写eq()的类需要保留父类的hash()的实现,则必须pass设置__hash__ = <ParentClass>.__hash__
明确地告诉解释器。
如果未覆盖eq()的类希望禁止哈希支持,则应在类定义中包含__hash__ = None
。定义自己的hash()显式引发TypeError的类将被isinstance(obj, collections.abc.Hashable)
调用错误地标识为可散列。
Note
默认情况下,str 和 bytes 对象的hash()值被“盐化”,具有不可预测的随机值。尽管它们在单个 Python 进程中保持不变,但在重复调用 Python 之间是不可预测的。
这旨在提供保护,防止由于精心选择的 Importing 而导致的拒绝服务,这些 Importing 利用了 dict 插入的最坏情况的性能 O(n ^ 2)复杂性。有关详情,请参见http://www.ocert.org/advisories/ocert-2011-003.html。
更改哈希值会影响集合的迭代 Sequences。 Python 从未保证过这种 Sequences(通常在 32 位和 64 位版本之间有所不同)。
另请参见 PYTHONHASHSEED。
在版本 3.3 中更改:默认情况下启用哈希随机化。
object.
__bool__
(* self *)
3.3.2. 自定义属性访问
可以定义以下方法来自定义类实例的属性访问(使用,分配或删除x.name
)的含义。
object.
__getattr__
(* self , name *)- 当默认属性访问失败并带有AttributeError时调用(getattribute()引发AttributeError,因为* name 不是实例属性或
self
的类树中的属性;或 name *属性的get()引发AttributeError)。此方法应返回(计算的)属性值或引发AttributeError异常。
- 当默认属性访问失败并带有AttributeError时调用(getattribute()引发AttributeError,因为* name 不是实例属性或
请注意,如果pass常规机制找到该属性,则不会调用getattr()。 (这是getattr()和setattr()之间的故意不对称。)这样做既出于效率考虑,又因为getattr()无法访问实例的其他属性。请注意,至少对于实例变量,您可以pass不在实例属性字典中插入任何值(而是将其插入另一个对象中)来伪造总体控制。有关实际获得对属性访问的完全控制的方法,请参见下面的getattribute()方法。
object.
__getattribute__
(* self , name *)- 无条件调用以实现类实例的属性访问。如果该类还定义getattr(),则除非getattribute()显式调用它或引发AttributeError,否则不会调用后者。此方法应返回(计算出的)属性值或引发AttributeError异常。为了避免此方法中的无限递归,其实现应始终调用具有相同名称的 Base Class 方法以访问其所需的任何属性,例如
object.__getattribute__(self, name)
。
- 无条件调用以实现类实例的属性访问。如果该类还定义getattr(),则除非getattribute()显式调用它或引发AttributeError,否则不会调用后者。此方法应返回(计算出的)属性值或引发AttributeError异常。为了避免此方法中的无限递归,其实现应始终调用具有相同名称的 Base Class 方法以访问其所需的任何属性,例如
Note
查找特殊方法时,由于pass语言语法或内置函数进行隐式调用的结果,仍可能会绕过此方法。参见特殊方法查找。
object.
__setattr__
(* self , name , value *)- try分配属性时调用。这被称为而不是常规机制(即,将值存储在实例字典中)。 * name 是属性名称, value *是要为其分配的值。
如果setattr()要分配给实例属性,则应使用相同的名称(例如object.__setattr__(self, name, value)
)调用 Base Class 方法。
object.
__delattr__
(* self , name *)- 类似于setattr(),但用于属性删除而不是分配。仅当
del obj.name
对对象有意义时,才应实现此目的。
- 类似于setattr(),但用于属性删除而不是分配。仅当
object.
__dir__
(* self *)
3.3.2.1. 定制模块属性访问
特殊名称__getattr__
和__dir__
也可以用于自定义对模块属性的访问。模块级别的__getattr__
函数应接受一个参数(即属性名称),并返回计算值或引发AttributeError。如果pass常规查找(即object.getattribute())在模块对象上未找到属性,则在提升AttributeError之前在模块__dict__
中搜索__getattr__
。如果找到,将使用属性名称调用它并返回结果。
__dir__
函数不应接受任何参数,并返回表示代表模块上可访问名称的字符串序列。如果存在,此Function将覆盖模块上的标准dir()搜索。
为了对模块行为(设置属性,属性等)进行更细粒度的自定义,可以将模块对象的__class__
属性设置为types.ModuleType的子类。例如:
import sys
from types import ModuleType
class VerboseModule(ModuleType):
def __repr__(self):
return f'Verbose {self.__name__}'
def __setattr__(self, attr, value):
print(f'Setting {attr}...')
super().__setattr__(attr, value)
sys.modules[__name__].__class__ = VerboseModule
Note
定义模块__getattr__
和设置模块__class__
仅会影响使用属性访问语法进行的查找-不影响直接访问模块全局变量(无论是pass模块内的代码还是pass对模块全局变量字典的引用)。
在版本 3.5 中更改:__class__
模块属性现在可写。
3.7 版中的新Function:__getattr__
和__dir__
模块属性。
See also
PEP 562-__getattr_和__dir_模块
描述模块上的
__getattr__
和__dir__
函数。
3.3.2.2. 实现 Descriptors
以下方法仅在包含该方法的类的实例(所谓的* descriptor 类)出现在 owner *类中时(Descriptors 必须位于所有者的类字典或类字典中的其中一个对象中)时适用它的 parent)。在下面的示例中,“属性”是指名称是所有者类'dict中的属性的键的属性。
object.
__get__
(* self , instance , owner = None *)- 调用以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问)。可选的* owner 参数是所有者类,而 instance 是pass属性访问属性的实例,当pass owner *访问属性时是
None
。
- 调用以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问)。可选的* owner 参数是所有者类,而 instance 是pass属性访问属性的实例,当pass owner *访问属性时是
此方法应返回计算出的属性值或引发AttributeError异常。
PEP 252指定可以使用一个或两个参数调用get()。 Python 自己的内置 Descriptors 支持此规范。但是,某些第三方工具可能具有需要两个参数的 Descriptors。无论是否需要,Python 自己的getattribute()实现总是传递两个参数。
object.
__set__
(* self , instance , value *)- 调用以将所有者类的实例* instance 上的属性设置为新值 value *。
注意,添加set()或delete()会将 Descriptors 的类型更改为“数据 Descriptors”。有关更多详细信息,请参见Invoking Descriptors。
object.
__delete__
(* self , instance *)- 调用以删除所有者类的实例* instance *上的属性。
object.
__set_name__
(* self , owner , name *)- 在创建拥有类* owner 时调用。Descriptors 已分配给 name *。
Note
set_name()仅作为type构造函数的一部分隐式调用,因此在初始创建后将 Descriptors 添加到类时,需要使用适当的参数显式调用set_name():
class A:
pass
descr = custom_descriptor()
A.attr = descr
descr.__set_name__(A, 'attr')
有关更多详细信息,请参见创建类对象。
3.6 版的新Function。
inspect模块将属性__objclass__
解释为指定定义该对象的类(正确设置此类可有助于动态类属性的运行时自省)。对于可调用对象,它可能指示给定类型(或子类)的实例作为第一个位置参数是期望的或必需的(例如,CPython 为在 C 中实现的未绑定方法设置此属性)。
3.3.2.3. 调用 Descriptors
通常,Descriptors 是具有“绑定行为”的对象属性,其属性访问已被 Descriptors 协议get(),set()和delete()中的方法所覆盖。如果为对象定义了这些方法中的任何一种,则称其为 Descriptors。
属性访问的默认行为是从对象的字典中获取,设置或删除属性。例如,a.x
的查找链从a.__dict__['x']
开始,然后是type(a).__dict__['x']
,并一直到type(a)
的 Base Class(不包括元类)continue。
但是,如果查找到的值是定义 Descriptors 方法之一的对象,则 Python 可能会覆盖默认行为并改为调用 Descriptors 方法。优先级链在何处发生取决于定义了哪些 Descriptors 方法以及如何调用它们。
Descriptors 调用的起点是绑定a.x
。参数的组合方式取决于a
:
Direct Call
- 最简单和最不常见的调用是在用户代码直接调用 Descriptors 方法
x.__get__(a)
时。
- 最简单和最不常见的调用是在用户代码直接调用 Descriptors 方法
Instance Binding
- 如果绑定到对象实例,则
a.x
转换为调用:type(a).__dict__['x'].__get__(a, type(a))
。
- 如果绑定到对象实例,则
Class Binding
- 如果绑定到一个类,则
A.x
转换为调用:A.__dict__['x'].__get__(None, A)
。
- 如果绑定到一个类,则
Super Binding
- 如果
a
是super的实例,则绑定super(B, obj).m()
在obj.__class__.__mro__
中搜索紧接B
之前的 Base ClassA
,然后pass调用A.__dict__['m'].__get__(obj, obj.__class__)
调用 Descriptors。
- 如果
对于实例绑定,Descriptors 调用的优先级取决于定义了哪些 Descriptors 方法。Descriptors 可以定义get(),set()和delete()的任意组合。如果未定义get(),则访问该属性将返回 Descriptors 对象本身,除非该对象的实例字典中有一个值。如果 Descriptors 定义set()和/或delete(),则它是数据 Descriptors;如果没有定义,则为非数据 Descriptors。通常,数据 Descriptors 同时定义get()和set(),而非数据 Descriptors 仅具有get()方法。定义了set()和get()的数据 Descriptors 始终会覆盖实例字典中的重定义。相反,非数据 Descriptors 可以被实例覆盖。
Python 方法(包括staticmethod()和classmethod())被实现为非数据 Descriptors。因此,实例可以重新定义和覆盖方法。这允许单个实例获取与同一类的其他实例不同的行为。
property()函数被实现为数据 Descriptors。因此,实例无法覆盖属性的行为。
3.3.2.4. slots
- __ slots __ 允许我们显式语句数据成员(如属性),并拒绝创建 __ dict __ 和 __ weakref __ (除非在 __ slots __ *中明确语句或在父级中可用)。
使用* __ dict __ *节省的空间可能很大。属性查找速度也可以大大提高。
object.
__slots__
- 可以为该类变量分配一个字符串,可迭代的字符串或具有实例使用的变量名称的字符串序列。 * __ slots __ 为语句的变量保留空间,并防止为每个实例自动创建 __ dict __ 和 __ weakref __ *。
3.3.2.4.1. 使用__slots_的注意事项
从没有* __ slots __ 的类继承时,实例的 __ dict __ 和 __ weakref __ *属性将始终可访问。
如果没有* __ dict __ 变量,则无法为实例分配 __ slots __ *定义中未列出的新变量。try分配给未列出的变量名会引发AttributeError。如果需要动态分配新变量,则在__slots __ *语句中的字符串序列中添加
'__dict__'
。对于每个实例,如果没有* __ weakref __ 变量,则定义 __ slots __ *的类将不支持对其实例的弱引用。如果需要弱引用支持,则在__slots __ *语句中的字符串序列中添加
'__weakref__'
。-
- __ slots __ 在类级别pass为每个变量名称创建 Descriptors(Implementing Descriptors)实现。结果,类属性不能用于为 __ slots __ *定义的实例变量设置默认值;否则,class 属性将覆盖 Descriptors 分配。
-
- __ slots __ 语句的操作不限于定义它的类。家长语句的 __ slots __ 在孩子类可用。但是,子子类将获得 __ dict __ 和 __ weakref __ ,除非它们还定义了 __ slots __ (它们应仅包含任何 additional *插槽的名称)。
如果一个类定义了也在 Base Class 中定义的插槽,则无法访问由 Base Class 插槽定义的实例变量(除非直接从 Base Class 中获取其 Descriptors)。这使程序的含义不确定。将来可能会添加检查以防止这种情况。
任何非字符串可迭代的对象都可以分配给* __ slots __ *。也可以使用 Map。但是,将来,可能会为每个键对应的值分配特殊含义。
-
- __ class __ 分配仅在两个类具有相同的 __ slots __ *时才有效。
可以使用具有多个带槽父类的多重继承,但是只允许一个父类具有由插槽创建的属性(其他 Base Class 必须具有空的插槽布局)-违反会引发TypeError。
如果将迭代器用于* __ slots __ ,则将为每个迭代器的值创建一个 Descriptors。但是, __ slots __ *属性将是一个空的迭代器。
3.3.3. 定制类创建
每当一个类从另一个类继承时,就会在该类上调用* __ init_subclass __ *。这样,可以编写更改子类行为的类。这与类装饰器密切相关,但是在类装饰器仅影响应用它们的特定类的情况下,__init_subclass__
仅适用于定义该方法的类的将来子类。
- 类方法
object.
__init_subclass__
(* cls *)- 只要包含类被子类化,就会调用此方法。 * cls *是新的子类。如果定义为普通实例方法,则此方法将隐式转换为类方法。
赋予新类的关键字参数将传递给父类__init_subclass__
。为了与使用__init_subclass__
的其他类兼容,应删除所需的关键字参数并将其他参数传递给 Base Class,如:
class Philosopher:
def __init_subclass__(cls, /, default_name, **kwargs):
super().__init_subclass__(**kwargs)
cls.default_name = default_name
class AustralianPhilosopher(Philosopher, default_name="Bruce"):
pass
默认实现object.__init_subclass__
不执行任何操作,但是如果使用任何参数调用它,都会引发错误。
Note
元类提示metaclass
被其余的类型机器使用,并且永远不会传递给__init_subclass__
实现。实际的元类(而不是显式提示)可以作为type(cls)
访问。
3.6 版的新Function。
3.3.3.1. Metaclasses
默认情况下,使用type()构造类。类主体在新的名称空间中执行,并且类名称在本地绑定到type(name, bases, namespace)
的结果。
可以pass在类定义行中传递metaclass
关键字参数来定制类创建过程,或者pass从包含此类参数的现有类继承来定制类创建过程。在以下示例中,MyClass
和MySubclass
都是Meta
的实例:
class Meta(type):
pass
class MyClass(metaclass=Meta):
pass
class MySubclass(MyClass):
pass
类定义中指定的任何其他关键字参数都将传递到下面描述的所有元类操作。
执行类定义时,将发生以下步骤:
MRO 条目已解决;
确定适当的元类;
类名称空间已准备好;
类体被执行;
创建了类对象。
3.3.3.2. 解决 MRO 条目
如果出现在类定义中的基不是type的实例,则在其上搜索__mro_entries__
方法。如果找到,则使用原始的基 Tuples 调用它。此方法必须返回将代替该基础使用的类的 Tuples。Tuples 可能为空,在这种情况下,原始基数将被忽略。
See also
PEP 560-键入模块和通用类型的核心支持
3.3.3.3. 确定适当的元类
确定类定义的适当元类如下:
如果没有给出基数也没有给出明确的元类,则使用type();
如果给出了显式元类,并且它不是type()的实例,那么它直接用作元类;
如果给定type()的实例作为显式元类,或者定义了基数,则使用派生程度最高的元类。
从派生的显式指定的元类(如果有的话)和所有指定的 Base Class 的元类(即type(cls)
)中选择派生程度最高的元类。最派生的元类是这些候选元类的* all *的子类型。如果所有候选元类都不满足该条件,则该类定义将以TypeError
失败。
3.3.3.4. 准备类名称空间
一旦标识了适当的元类,就准备好类名称空间。如果元类具有__prepare__
属性,则将其称为namespace = metaclass.__prepare__(name, bases, **kwds)
(其中其他关键字参数(如果有)来自类定义)。 __prepare__
方法应实现为classmethod()。 __prepare__
返回的名称空间将传递到__new__
,但是在创建finally类对象时,会将名称空间复制到新的dict
中。
如果元类没有__prepare__
属性,则将类名称空间初始化为空的有序 Map。
See also
PEP 3115-Python 3000 中的元类
引入了
__prepare__
名称空间钩子
3.3.3.5. 执行类机构
类主体(大约)以exec(body, globals(), namespace)
的形式执行。与正常调用exec()的主要区别在于,词法作用域允许类主体(包括任何方法)在类定义出现在函数内部时引用当前作用域和外部作用域的名称。
但是,即使类定义发生在函数内部,在类内部定义的方法仍然看不到在类作用域定义的名称。必须pass实例或类方法的第一个参数或下一节中描述的隐式词法作用域__class__
引用来访问类变量。
3.3.3.6. 创建类对象
pass执行类主体填充了类名称空间后,将pass调用metaclass(name, bases, namespace, **kwds)
创建类对象(此处传递的其他关键字与传递给__prepare__
的关键字相同)。
该类对象是零参数形式super()引用的对象。如果类主体中的任何方法引用__class__
或super
,则__class__
是编译器创建的隐式闭包引用。这允许super()的零参数形式根据词法作用域正确识别正在定义的类,而用于进行当前调用的类或实例是根据传递给该方法的第一个参数来识别的。
CPython 实现细节: 在 CPython 3.6 和更高版本中,__class__
单元格作为类命名空间中的__classcell__
条目传递给元类。如果存在,则必须将该消息传播到type.__new__
调用,才能正确初始化该类。否则,Python 3.8 的结果将为RuntimeError。
当使用默认元类type或finally调用type.__new__
的任何元类时,在创建类对象后将调用以下其他自定义步骤:
首先,
type.__new__
收集了类命名空间中定义set_name()方法的所有 Descriptors;第二,调用所有这些
__set_name__
方法,并定义类和该特定 Descriptors 的分配名称;最后,在新类的直接父级上以其方法解析 Sequences 调用init_subclass()钩子。
创建类对象后,将其传递给类定义中包含的类装饰器(如果有),并将生成的对象作为定义的类绑定在本地名称空间中。
当使用type.__new__
创建新类时,作为名称空间参数提供的对象将被复制到新的有序 Map 中,而原始对象将被丢弃。新副本包装在只读代理中,该代理成为类对象的dict属性。
See also
PEP 3135-新超级
描述隐式的
__class__
闭包引用
3.3.3.7. 用于元类
元类的潜在用途是无限的。已探索的一些想法包括枚举,日志记录,接口检查,自动委派,自动属性创建,代理,框架和自动资源锁定/同步。
3.3.4. 自定义实例和子类检查
以下方法用于覆盖isinstance()和issubclass()内置函数的默认行为。
特别是,元类abc.ABCMeta实现了这些方法,以便允许将抽象 Base Class(ABC)作为“虚拟 Base Class”添加到任何类或类型(包括内置类型),包括其他 ABC。
class.
__instancecheck__
(* self , instance *)- 如果应将* instance 视为 class *的(直接或间接)实例,则返回 true。如果定义,则调用以实现
isinstance(instance, class)
。
- 如果应将* instance 视为 class *的(直接或间接)实例,则返回 true。如果定义,则调用以实现
class.
__subclasscheck__
(* self , subclass *)- 如果* subclass 应该被视为 class *的(直接或间接)子类,则返回 true。如果定义,则调用以实现
issubclass(subclass, class)
。
- 如果* subclass 应该被视为 class *的(直接或间接)子类,则返回 true。如果定义,则调用以实现
请注意,这些方法是在类的类型(元类)上查找的。它们不能在实际的类中定义为类方法。这与在实例上调用的特殊方法的查找一致,仅在这种情况下,实例本身是一个类。
See also
PEP 3119-介绍抽象 Base Class
包括用于passinstancecheck()和subclasscheck()自定义isinstance()和issubclass()行为的规范,并在向该语言添加抽象 Base Class(请参见abc模块)的情况下激发了该Function。
3.3.5. 模拟通用类型
可以pass定义一种特殊方法来实现 PEP 484(例如List[int]
)指定的通用类语法:
- 类方法
object.
__class_getitem__
(* cls , key *)- 返回一个对象,该对象pass* key *中的类型参数表示泛型类的专业化。
该方法在类对象本身上查找,并且在类主体中定义时,该方法隐式为类方法。注意,该机制主要保留给静态类型提示使用,不建议其他用法。
See also
PEP 560-键入模块和通用类型的核心支持
3.3.6. 模拟可调用对象
object.
__call__
(* self * [,* args ... *])- 当实例被“调用”为函数时调用;如果定义了此方法,则
x(arg1, arg2, ...)
是x.__call__(arg1, arg2, ...)
的简写。
- 当实例被“调用”为函数时调用;如果定义了此方法,则
3.3.7. 模拟容器类型
可以定义以下方法来实现容器对象。容器通常是序列(例如列表或 Tuples)或 Map(例如字典),但也可以表示其他容器。第一组方法用于仿真序列或仿真 Map。区别在于,对于序列,允许的键应为整数* k ,其中0 <= k < N
为整数,其中 N *是序列的长度,或者是切片对象,它们定义项的范围。还建议 Map 提供的方法keys()
,values()
,items()
,get()
,clear()
,setdefault()
,pop()
,popitem()
,copy()
和update()
的行为与 Python 的标准字典对象相似。 collections.abc模块提供MutableMapping抽象 Base Class,以帮助从getitem(),setitem(),delitem()和keys()
的基集创建这些方法。可变序列应提供append()
,count()
,index()
,extend()
,insert()
,pop()
,remove()
,reverse()
和sort()
的方法,例如 Python 标准列表对象。最后,序列类型应pass定义以下所述的方法add(),radd(),iadd(),mul(),rmul()和imul()来实现加法(表示串联)和乘法(表示重复);他们不应该定义其他数值运算符。建议 Map 和序列都实现contains()方法,以允许有效使用in
运算符。对于 Map,in
应该搜索 Map 的键;对于序列,它应该搜索值。进一步建议 Map 和序列都实现iter()方法,以允许pass容器进行有效的迭代。对于 Map,iter()应该遍历对象的键;对于序列,它应该遍历值。
object.
__len__
(* self *)
CPython 实现细节: 在 CPython 中,长度最大为sys.maxsize。如果长度大于sys.maxsize
,则某些要素(例如len())可能会升高OverflowError。为了防止pass真值测试提高OverflowError
,对象必须定义bool()方法。
object.
__length_hint__
(* self *)- 调用以实现operator.length_hint()。应该返回对象的估计长度(可以大于或小于实际长度)。长度必须是
>=
0 的整数。返回值也可以是NotImplemented,其处理方式与__length_hint__
方法根本不存在一样。此方法纯粹是一种优化,对于正确性从不需要。
- 调用以实现operator.length_hint()。应该返回对象的估计长度(可以大于或小于实际长度)。长度必须是
3.4 版的新Function。
Note
切片专用于以下三种方法。像这样的电话
a[1:2] = b
被翻译成
a[slice(1, 2, None)] = b
等等。缺少的切片项目始终使用None
填充。
object.
__getitem__
(* self , key *)- 调用以实现
self[key]
的评估。对于序列类型,可接受的键应为整数和切片对象。请注意,对负索引的特殊解释(如果类希望模拟序列类型)取决于getitem()方法。如果* key 类型不合适,则可能会引发TypeError;如果该值超出了该序列的索引集(在对负值进行任何特殊解释之后),则应加IndexError。对于 Map 类型,如果缺少 key *(不在容器中),则应加KeyError。
- 调用以实现
Note
for循环期望为非法索引引发IndexError,以允许正确检测序列的结尾。
object.
__setitem__
(* self , key , value *)object.
__delitem__
(* self , key *)object.
__missing__
(* self , key *)object.
__iter__
(* self *)- 当容器需要迭代器时,将调用此方法。此方法应返回一个新的迭代器对象,该对象可以遍历容器中的所有对象。对于 Map,它应该遍历容器的键。
迭代器对象也需要实现此方法;他们必须返回自己。有关迭代器对象的更多信息,请参见Iterator Types。
object.
__reversed__
(* self *)- 内置reversed()调用(如果存在)以实现反向迭代。它应该返回一个新的迭代器对象,该对象以相反的 Sequences 遍历容器中的所有对象。
如果未提供reversed()方法,则内置reversed()将回退到使用序列协议(len()和getitem())。支持序列协议的对象只有在提供比reversed()提供的实现效率更高的实现时,才应提供reversed()。
成员资格测试运算符(in和not in)通常作为pass容器的迭代来实现。但是,容器对象可以为以下特殊方法提供更有效的实现,这也不要求对象是可迭代的。
object.
__contains__
(* self , item *)- 要求实施成员资格测试操作员。如果* item 在 self *中,则应返回 true,否则返回 false。对于 Map 对象,应考虑 Map 的键而不是值或键-项对。
对于未定义contains()的对象,成员资格测试首先passiter()try迭代,然后passgetitem()try旧的序列迭代协议,请参见语言参考中的本节。
3.3.8. 模拟数值类型
可以定义以下方法来模拟数字对象。与未实现的特定种类的数字不支持的操作相对应的方法(例如,非整数的按位运算)应保持未定义状态。
object.
__add__
(* self , other *)object.
__sub__
(* self , other *)object.
__mul__
(* self , other *)object.
__matmul__
(* self , other *)object.
__truediv__
(* self , other *)object.
__floordiv__
(* self , other *)object.
__mod__
(* self , other *)object.
__divmod__
(* self , other *)object.
__pow__
(* self , other * [,* modulo *])object.
__lshift__
(* self , other *)object.
__rshift__
(* self , other *)object.
__and__
(* self , other *)object.
__xor__
(* self , other *)object.
__or__
(* self , other *)
如果这些方法之一不支持使用提供的参数进行的操作,则应返回NotImplemented
。
object.
__radd__
(* self , other *)object.
__rsub__
(* self , other *)object.
__rmul__
(* self , other *)object.
__rmatmul__
(* self , other *)object.
__rtruediv__
(* self , other *)object.
__rfloordiv__
(* self , other *)object.
__rmod__
(* self , other *)object.
__rdivmod__
(* self , other *)object.
__rpow__
(* self , other * [,* modulo *])object.
__rlshift__
(* self , other *)object.
__rrshift__
(* self , other *)object.
__rand__
(* self , other *)object.
__rxor__
(* self , other *)object.
__ror__
(* self , other *)
请注意,三 Tuplespow()不会try调用rpow()(强制性规则会变得过于复杂)。
Note
如果右操作数的类型是左操作数类型的子类,并且该子类为操作提供了反射方法,则将在左操作数的非反射方法之前调用此方法。此行为允许子类覆盖其祖先的操作。
object.
__iadd__
(* self , other *)object.
__isub__
(* self , other *)object.
__imul__
(* self , other *)object.
__imatmul__
(* self , other *)object.
__itruediv__
(* self , other *)object.
__ifloordiv__
(* self , other *)object.
__imod__
(* self , other *)object.
__ipow__
(* self , other * [,* modulo *])object.
__ilshift__
(* self , other *)object.
__irshift__
(* self , other *)object.
__iand__
(* self , other *)object.
__ixor__
(* self , other *)object.
__ior__
(* self , other *)- 调用这些方法以实现增强的算术分配(
+=
,-=
,*=
,@=
,/=
,//=
,%=
,**=
,<<=
,>>=
,&=
,^=
,|=
)。这些方法应try就地进行操作(修改* self )并返回结果(可以是但不一定是 self )。如果未定义特定方法,则扩展分配将回退到常规方法。例如,如果 x *是具有iadd()方法的类的实例,则x += y
等效于x = x.__iadd__(y)
。否则,与x + y
的评估一样,将考虑x.__add__(y)
和y.__radd__(x)
。在某些情况下,扩充分配可能会导致意外错误(请参阅当加法有效时,为什么 a_tuple [i] = ['item']引发异常?),但是此行为实际上是数据模型的一部分。
- 调用这些方法以实现增强的算术分配(
object.
__neg__
(* self *)object.
__pos__
(* self *)object.
__abs__
(* self *)object.
__invert__
(* self *)- 调用以实现一元算术运算(
-
,+
,abs()和~
)。
- 调用以实现一元算术运算(
object.
__complex__
(* self *)object.
__int__
(* self *)object.
__float__
(* self *)
object.
__index__
(* self *)- 被调用以实现operator.index(),并且在 Python 需要将数字对象无损地转换为整数对象时(例如在切片中或在内置的bin(),hex()和oct()函数中)调用。存在此方法表示数字对象是整数类型。必须返回一个整数。
如果未定义int(),float()和complex(),则相应的内置函数int(),float()和complex()会退回到index()。
object.
__round__
(* self * [,* ndigits *])object.
__trunc__
(* self *)object.
__floor__
(* self *)object.
__ceil__
(* self *)
如果未定义int(),则内置函数int()会退回到trunc()。
3.3.9. 使用语句上下文 Management 器
- context manager *是一个对象,定义执行with语句时要构建的运行时上下文。上下文 Management 器处理执行代码块所需的运行时上下文的入口和 Export。通常使用
with
语句(在with 语句部分中进行了描述)调用上下文 Management 器,但是也可以pass直接调用其方法来使用上下文 Management 器。
上下文 Management 器的典型用法包括保存和还原各种全局状态,锁定和解锁资源,关闭打开的文件等。
有关上下文 Management 器的更多信息,请参见上下文 Management 器类型。
object.
__enter__
(* self *)- Importing 与此对象相关的运行时上下文。 with语句会将此方法的返回值绑定到该语句的
as
子句中指定的目标(如果有)。
- Importing 与此对象相关的运行时上下文。 with语句会将此方法的返回值绑定到该语句的
object.
__exit__
(* self , exc_type , exc_value , traceback *)- 退出与此对象相关的运行时上下文。这些参数描述了导致退出上下文的异常。如果上下文无 exception 地退出,则所有三个参数均为None。
如果提供了异常,并且该方法希望抑制该异常(即,防止其传播),则它应返回一个真值。否则,将在退出此方法后正常处理异常。
请注意,exit()个方法不应引发传入的异常。这是呼叫者的责任。
3.3.10. 特殊方法查找
对于自定义类,只有在对对象的类型(而不是在对象的实例字典中)进行定义的情况下,才能保证对特殊方法的隐式调用可以正常工作。该行为是以下代码引发异常的原因:
>>> class C:
... pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()
此行为背后的基本原理是由所有特殊对象(包括类型对象)实现的许多特殊方法,例如hash()和repr()。如果这些方法的隐式查找使用常规查找过程,则在对类型对象本身进行调用时它们将失败:
>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument
以这种方式错误地try调用类的未绑定方法有时被称为“元类混淆”,pass在查找特殊方法时绕过实例可以避免这种情况:
>>> type(1).__hash__(1) == hash(1)
True
>>> type(int).__hash__(int) == hash(int)
True
除了出于正确性的考虑绕过任何实例属性之外,隐式特殊方法查找通常还绕过getattribute()方法,甚至对象的元类也是如此:
>>> class Meta(type):
... def __getattribute__(*args):
... print("Metaclass getattribute invoked")
... return type.__getattribute__(*args)
...
>>> class C(object, metaclass=Meta):
... def __len__(self):
... return 10
... def __getattribute__(*args):
... print("Class getattribute invoked")
... return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__() # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c) # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c) # Implicit lookup
10
以这种方式绕过getattribute()机器为解释器内的速度优化提供了很大的空间,但以牺牲一些特殊方法的处理为代价(特殊方法必须在类对象本身上设置,以便被一致地调用)Interpreter)。
3.4. Coroutines
3.4.1. await 的对象
awaitable对象通常实现await()方法。从async def函数返回的Coroutine对象是可以 await 的。
Note
从带有types.coroutine()或asyncio.coroutine()装饰的生成器返回的generator iterator对象也是可以 await 的,但是它们不实现await()。
object.
__await__
(* self *)- 必须返回iterator。应该用于实现awaitable对象。例如,asyncio.Future实现此方法与await表达式兼容。
3.5 版中的新Function。
See also
PEP 492了解有关 await 对象的其他信息。
3.4.2. 协程对象
Coroutine个对象是awaitable个对象。协程的执行可以pass调用await()并遍历结果来控制。当协程完成执行并返回时,迭代器将引发StopIteration,并且异常的value
属性保存返回值。如果协程引发异常,则它由迭代器传播。协程不应直接引发未处理的StopIteration异常。
协程还具有以下列出的方法,类似于生成器的方法(请参见Generator-iterator methods)。但是,与生成器不同,协程不直接支持迭代。
在版本 3.5.2 中进行了更改:多次 await 协程是RuntimeError。
coroutine.
send
(* value *)- 开始或恢复协程的执行。如果* value 为
None
,则相当于推进await()返回的迭代器。如果 value *不是None
,则此方法委托导致迭代器挂起的迭代器的send()方法。结果(返回值,StopIteration或其他异常)与如上所述对await()返回值进行迭代时相同。
- 开始或恢复协程的执行。如果* value 为
coroutine.
throw
(* type * [,* value * [,* traceback *]])- 在协程中引发指定的异常。该方法委托导致协程暂停的迭代器的throw()方法(如果有)。否则,将在挂起点引发异常。结果(返回值StopIteration或其他异常)与如上所述对await()返回值进行迭代时相同。如果协程中未捕获到异常,它将传播回调用方。
coroutine.
close
( )- 使协程自动清理并退出。如果协程已暂停,则此方法首先委托导致协程暂停的迭代器的close()方法(如果有)。然后,它在悬浮点升起GeneratorExit,从而使协程立即进行自我清理。最后,协程被标记为完成执行,即使它从未启动。
当协程对象即将被销毁时,它们会pass上述过程自动关闭。
3.4.3. 异步迭代器
异步迭代器可以在其__anext__
方法中调用异步代码。
可以在async for语句中使用异步迭代器。
object.
__aiter__
(* self *)- 必须返回异步迭代器对象。
object.
__anext__
(* self *)- 必须返回一个* awaitable *,导致迭代器的下一个值。迭代结束时应引发StopAsyncIteration错误。
异步可迭代对象的示例:
class Reader:
async def readline(self):
...
def __aiter__(self):
return self
async def __anext__(self):
val = await self.readline()
if val == b'':
raise StopAsyncIteration
return val
3.5 版中的新Function。
在 3.7 版中进行了更改:在 Python 3.7 之前,__aiter__
可以返回* awaitable *,它将解析为asynchronous iterator。
从 Python 3.7 开始,__aiter__
必须返回一个异步迭代器对象。返回任何其他内容将导致TypeError错误。
3.4.4. 异步上下文 Management 器
异步上下文 Management 器是上下文 Management 器,它能够以其__aenter__
和__aexit__
方法中止执行。
可以在async with语句中使用异步上下文 Management 器。
object.
__aenter__
(* self *)- 在语义上类似于enter(),唯一的区别是它必须返回* awaitable *。
object.
__aexit__
(* self , exc_type , exc_value , traceback *)- 在语义上类似于exit(),唯一的区别是它必须返回* awaitable *。
异步上下文 Management 器类的示例:
class AsyncContextManager:
async def __aenter__(self):
await log('entering context')
async def __aexit__(self, exc_type, exc, tb):
await log('exiting context')
3.5 版中的新Function。
Footnotes
-
- 在某些情况下,在某些受控条件下,有可能更改对象的类型。但是,通常这不是一个好主意,因为如果处理不当,它可能会导致某些非常奇怪的行为。
-
- hash(),iter(),reversed()和contains()方法对此有特殊的处理;其他人仍会引发TypeError,但可以依靠
None
不可调用的行为来这样做。
- hash(),iter(),reversed()和contains()方法对此有特殊的处理;其他人仍会引发TypeError,但可以依靠
-
- 这里的“不支持”表示该类没有这样的方法,或者该方法返回
NotImplemented
。如果要强制回退到正确的操作数的反射方法,请不要将方法设置为None
,这将具有显着阻止此类回退的相反效果。
- 这里的“不支持”表示该类没有这样的方法,或者该方法返回
-
- 对于相同类型的操作数,假定如果非反射方法(例如add())失败,则不支持该操作,这就是为什么不调用反射方法的原因。