python / 3.7.2rc1 / all / reference-datamodel.html

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可能会使通常可以收集的对象保持活动状态。另请注意,使用'tryexcept'语句捕获异常可能会使对象保持活动状态。

一些对象包含对“外部”资源的引用,例如打开的文件或窗口。可以理解,在垃圾回收对象时释放了这些资源,但是由于不能保证垃圾回收的发生,因此此类对象还提供了一种释放外部资源的显式方式,通常是close()方法。强烈建议使用程序显式关闭此类对象。 'tryfinally'语句和'with'语句提供了方便的方法。

一些对象包含对其他对象的引用。这些被称为容器。容器的示例是 Tuples,列表和字典。引用是容器值的一部分。在大多数情况下,当我们谈论容器的值时,我们暗含的是值,而不是所包含对象的标识。但是,当我们谈论容器的可变性时,仅隐含了直接包含的对象的身份。因此,如果不可变容器(如 Tuples)包含对可变对象的引用,则当该可变对象更改时,其值也会更改。

类型影响对象行为的几乎所有方面。甚至对象标识的重要性在某种意义上也受到影响:对于不可变类型,计算新值的操作实际上可能返回对具有相同类型和值的任何现有对象的引用,而对于可变对象,则不允许这样做。例如,根据实现的不同,在a = 1; b = 1ab之后可能会或可能不会使用值 1 引用相同的对象,但是在c = []; d = []之后,cd被保证引用了两个不同的,唯一的,新创建的空列表。 (请注意c = d = []将相同的对象分配给cd.)

3.2. 标准类型层次结构

以下是 Python 内置的类型的列表。扩展模块(使用 C,Java 或其他语言编写,取决于实现)可以定义其他类型。Future 的 Python 版本可能会在类型层次结构中添加类型(例如,有理数,有效存储的整数数组等),尽管通常会pass标准库提供此类添加。

下面的某些类型描述包含一个列出“特殊属性”的段落。这些是提供对实现的访问的属性,并不旨在用于一般用途。他们的定义将来可能会改变。

  • None

    • 此类型具有单个值。有一个具有此值的对象。pass内置名称None访问此对象。它用于表示在许多情况下不存在值,例如,它是从未显式返回任何内容的函数中返回的。其真实值是错误的。
  • NotImplemented

    • 此类型具有单个值。有一个具有此值的对象。pass内置名称NotImplemented访问此对象。如果数字方法和丰富比较方法未实现所提供操作数的操作,则应返回此值。 (然后,解释程序将根据操作员try执行反射操作或其他回退.)其真实值是 true。

有关更多详细信息,请参见实施算术运算

  • Ellipsis

    • 此类型具有单个值。有一个具有此值的对象。pass Literals...或内置名称Ellipsis访问该对象。它的真实价值是真实的。
  • numbers.Number

    • 它们由数字 Literals 创建,并由算术运算符和算术内置函数作为结果返回。数字对象是不可变的。一旦 Creating 了价值,就永远不会改变。 Python 数字当然与 math 数字密切相关,但受到计算机中数字表示形式的限制。

Python 区分整数,浮点数和复数:

  • numbers.Integral

    • 这些代表整数 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\.
    

整数表示规则旨在对涉及负整数的移位和掩码运算提供最有意义的解释。

  • numbers.Real ( float)

    • 这些代表机器级别的双精度浮点数。您只能接受底层计算机体系结构(以及 C 或 Java 实现)的接受范围和溢出处理。 Python 不支持单精度浮点数;节省处理器和内存使用量(通常是使用它们的原因)与在 Python 中使用对象的开销相形见,,因此没有理由使该语言复杂化为两种浮点数。
  • numbers.Complex ( complex)

    • 这些将复数表示为Pair机器级双精度浮点数。浮点数的注意事项相同。可以pass只读属性z.realz.imag检索复数z的实部和虚部。
  • Sequences

    • 这些代表由非负数索引的有限有序集。内置函数len()返回序列的项数。当序列的长度为* n 时,索引集包含数字 0、1,…, n * -1.序列* a 的项目 i *由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\.

扩展模块arraycollections模块一样,提供了可变序列类型的其他示例。

  • Set types

    • 这些代表无序,有限的唯一不变对象集。因此,它们不能由任何下标索引。但是,可以对其进行迭代,并且内置函数len()返回集合中的项目数。集的常见用途是快速成员资格测试,从序列中删除重复项以及计算 math 运算(例如交集,并集,差和对称差)。

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

当前有两种内部集类型:

  • Sets

    • 这些代表可变的集合。它们是由内置的set()构造函数创建的,之后可以pass多种方法(例如add())进行修改。
  • Frozen sets

    • 这些代表一个不变的集合。它们由内置的frozenset()构造函数创建。由于冻结集是不可变的且是hashable,因此它可以再次用作另一个集的元素或用作字典键。
  • Mappings

    • 这些代表由任意索引集索引的对象的有限集。下标符号a[k]从 Mapa中选择由k索引的项目;可以在表达式中使用,也可以将其用作赋值或del语句的目标。内置函数len()返回 Map 中的项目数。

当前只有一种内部 Map 类型:

  • Dictionaries

    • 这些代表由几乎任意值索引的有限对象集。唯一不可接受作为键的值类型是包含列表或字典或其他可变类型的值,这些值或值是按值而不是对象标识进行比较的,原因是字典的有效实现需要键的哈希值保持不变。用于键的数字类型遵循数字比较的一般规则:如果两个数字比较相等(例如11.0),则可以互换使用它们来索引相同的字典条目。

字典保留插入 Sequences,这意味着将按照在字典上 Sequences 添加键的 Sequences 生成键。替换现有密钥不会改变 Sequences,但是删除密钥并重新插入会将其添加到末尾,而不是保留其旧位置。

字典是可变的;可以使用{...}表示法创建它们(请参见Dictionary displays部分)。

扩展模块dbm.ndbmdbm.gnucollections模块一样,提供了 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()的定义的类,并且xC的实例时,调用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异常,并且迭代器将到达要返回的值集的结尾。
  • 异步 Generator Function

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

调用异步迭代器的aiterator.__anext__()方法将返回awaitable,它将在 await 时执行,直到使用yield表达式提供值为止。当函数执行空的return语句或结束结尾时,将引发StopAsyncIteration异常,并且异步迭代器将到达要产生的值集的末尾。

  • Built-in functions

    • 内置函数对象是 C 函数的包装器。内置函数的示例是len()math.sin()(math是标准的内置模块)。参数的数量和类型由 C 函数确定。特殊的只读属性:__doc__是函数的文档字符串,或None(如果不可用); name是函数的名称; __self__设置为None(但请参见下一项); __module__是定义Function的模块的名称,或None(如果不可用)。
  • Built-in methods

    • 这实际上是内置函数的另一种伪装,这次包含一个作为隐式额外参数传递给 C 函数的对象。内置方法的一个示例是alist.append(),假设* alist 是列表对象。在这种情况下,特殊的只读属性__self__被设置为 alist *表示的对象。
  • Classes

    • 类是可调用的。这些对象通常充当其自身新实例的工厂,但是覆盖new()的类类型也可以进行变化。调用的参数将传递给new(),在典型情况下,传递给init()以初始化新实例。
  • Class Instances

    • pass在类中定义call()方法,可以使任意类的实例可调用。
  • Modules

    • 模块是 Python 代码的基本组织单位,由import语句调用的import system或调用importlib.import_module()和内置import()之类的函数来创建。模块对象具有由字典对象实现的名称空间(这是由模块中定义的函数的__globals__属性引用的字典)。将属性引用转换为此字典中的查找,例如m.x等效于m.__dict__["x"]。模块对象不包含用于初始化模块的代码对象(因为一旦完成初始化就不需要它)。

属性分配会更新模块的名称空间字典,例如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 版本附带的文档中找到。

当类属性引用(例如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()方法,则调用该方法以满足查找。

属性分配和删除将更新实例的字典,而不会更新类的字典。如果该类具有setattr()delattr()方法,则将调用此方法,而不是直接更新实例字典。

如果类实例具有使用某些特殊名称的方法,则它们可以 Feign 为数字,序列或 Map。参见特殊方法名称部分。

特殊属性:dict是属性字典; class是实例的类。

  • I/O 对象(也称为文件对象)

    • file object代表打开的文件。可以使用各种快捷方式来创建文件对象:open()内置函数,以及套接字对象的os.popen()os.fdopen()makefile()方法(可能还有其他Function或扩展模块提供的方法)。

对象sys.stdinsys.stdoutsys.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 中使用了0x100x1000位。

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属性。

  • Slice objects

    • 切片对象用于表示getitem()方法的切片。它们也由内置的slice()函数创建。

特殊的只读属性: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)。除非另有说明,否则当未定义适当的方法(通常为AttributeErrorTypeError)时,try执行操作会引发异常。

将特殊方法设置为None表示相应的操作不可用。例如,如果一个类将iter()设置为None,则该类是不可迭代的,因此在其实例上调用iter()将引发TypeError(而不会退回到getitem())。 [2]

当实现模拟任何内置类型的类时,重要的是,仅在对要建模的对象有意义的程度上实现模拟。例如,某些序列可能适用于单个元素的检索,但是提取切片可能没有意义。 (一个示例是 W3C 的文档对象模型中的NodeList接口.)

3.3.1. 基本定制

  • object. __new__(* cls * [,* ... *])
    • 调用以创建类* cls 的新实例。 new()是一个静态方法(特殊情况,因此您无需这样语句),它将实例被请求的类作为其第一个参数。其余参数是传递给对象构造函数表达式(对类的调用)的参数。返回值new()应该是新的对象实例(通常是 cls *的实例)。

典型实现pass使用带有适当参数的super().__new__(cls[, ...])调用超类的new()方法来创建类的新实例,然后在返回之前根据需要修改新创建的实例。

如果在对象构造期间调用new()并返回* cls 的实例或子类,则将像__init__(self[, ...])一样调用新实例的init()方法,其中 self *是新实例,其余参数与传递给的参数相同。对象构造函数。

如果new()不返回* cls *实例,则将不会调用新实例的init()方法。

new()主要用于允许不可变类型(例如 int,str 或 tuple)的子类自定义实例创建。为了自定义类的创建,通常也将其覆盖在自定义元类中。

  • object. __init__(* self * [,* ... *])
    • 在创建实例之后(由new()调用),但在实例返回给调用者之前调用。参数是传递给类构造函数表达式的参数。如果 Base Class 具有init()方法,则派生类的init()方法(如果有的话)必须显式调用它,以确保实例的 Base Class 部分的正确初始化。例如:super().__init__([args...])

因为new()init()在构造对象时一起工作(使用new()创建它,用init()对其进行自定义),所以init()不会返回任何非None的值;这样做将导致在运行时引发TypeError

  • object. __del__(* self *)
    • 在实例即将销毁时调用。这也称为终结器或(不当地)析构函数。如果 Base Class 具有del()方法,则派生类的del()方法(如果有)必须显式调用它,以确保正确删除实例的 Base Class 部分。

del()方法有可能(尽管不建议使用!)pass创建对实例的新引用来推迟实例的销毁。这称为对象复活。当即将复活的对象即将被销毁时,是否再次调用del()取决于实现方式。当前的CPython实现仅调用一次。

不能保证在解释器退出时仍然为存在的对象调用del()方法。

Note

del x不会直接调用x.__del__()-前者将x的引用计数减一,而后者仅在x的引用计数达到零时才调用。

CPython 实现细节: 引用循环有可能防止对象的引用计数变为零。在这种情况下,该周期将稍后被循环垃圾收集器检测并删除。引用循环的常见原因是局部变量中捕获了异常。然后,框架的本地变量引用该异常,该异常引用其自身的回溯,该异常引用引用回溯中捕获的所有帧的局部变量。

See also

gc模块的文档。

Warning

由于调用del()方法的情况不稳定,在执行过程中发生的异常将被忽略,并向sys.stderr打印警告。特别是:

  • 当执行任意代码(包括来自任意线程的代码)时,可以调用del()。如果del()需要进行锁定或调用任何其他阻塞资源,则该死锁可能会死锁,因为该资源可能已被执行del()的break代码所占用。

  • del()可以在解释器关闭期间执行。结果,它需要访问的全局变量(包括其他模块)可能已被删除或设置为None。 Python 保证,在删除其他全局变量之前,将从其模块中删除名称以单个下划线开头的全局变量;如果不存在对此类全局变量的其他引用,则这可能有助于确保在调用del()方法时导入的模块仍然可用。

  • object. __repr__(* self *)
    • repr()内置函数调用以计算对象的“正式”字符串表示形式。如果可能的话,这应该看起来像一个有效的 Python 表达式,可用于重新创建具有相同值的对象(给定适当的环境)。如果这不可能,则应返回格式为<...some useful description...>的字符串。返回值必须是一个字符串对象。如果一个类定义repr()而不是str(),则当需要该类实例的“非正式”字符串表示形式时,也使用repr()

这通常用于调试,因此重要的是,表示形式必须信息丰富且明确。

  • object. __str__(* self *)
    • str(object)和内置函数format()print()调用,以计算对象的“非正式”或可很好打印的字符串表示形式。返回值必须是string对象。

此方法与object.repr()的不同之处在于,不期望str()返回有效的 Python 表达式:可以使用更方便或更简洁的表示形式。

内置类型object定义的默认实现调用object.repr()

  • object. __bytes__(* self *)
    • bytes调用以计算对象的字节字符串表示形式。这应该返回一个bytes对象。
  • object. __format__(* self format_spec *)
    • format()内置函数调用,并pass扩展对格式化的字符串 Literalsstr.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。按照惯例,返回FalseTrue以进行成功比较。但是,这些方法可以返回任何值,因此,如果在布尔上下文中使用比较运算符(例如,在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 *)
    • 由内置函数hash()调用,用于对哈希集合的成员(包括setfrozensetdict)进行操作。 hash()应该返回一个整数。唯一需要的属性是比较相等的对象具有相同的哈希值。建议将对象的组成部分的哈希值混合在一起,方法是将它们打包成一个 Tuples 并哈希该 Tuples,从而在对象比较中也发挥作用。例:
def __hash__(self):
    return hash((self.name, self.nick, self.color))

Note

hash()将对象的自定义hash()方法返回的值截断为Py_ssize_t的大小。在 64 位版本中,通常为 8 个字节;在 32 位版本中,通常为 4 个字节。如果对象的hash()必须在不同位大小的版本上互操作,请确保检查所有受支持版本的宽度。一个简单的方法是python -c "import sys; print(sys.hash_info.width)"

如果一个类没有定义eq()方法,那么它也不应该定义hash()操作。如果它定义eq()而不是hash(),则其实例将不能用作可散列集合中的项目。如果一个类定义了可变对象并实现了eq()方法,则不应实现hash(),因为可哈希集合的实现要求键的哈希值是不可变的(如果对象的哈希值发生更改,则它将位于错误的哈希存储桶中)。

用户定义的类默认情况下具有eq()hash()方法。使用它们,所有对象比较不相等(除了它们本身),并且x.__hash__()返回适当的值,以使x == y暗示x is yhash(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 *)
    • 调用以实现真值测试和内置操作bool();应该返回FalseTrue。如果未定义此方法,则调用len()(如果已定义),并且如果其结果为非零,则认为该对象为 true。如果一个类既未定义len()也未定义bool(),则其所有实例均被视为 true。

3.3.2. 自定义属性访问

可以定义以下方法来自定义类实例的属性访问(使用,分配或删除x.name)的含义。

请注意,如果pass常规机制找到该属性,则不会调用getattr()。 (这是getattr()setattr()之间的故意不对称。)这样做既出于效率考虑,又因为getattr()无法访问实例的其他属性。请注意,至少对于实例变量,您可以pass不在实例属性字典中插入任何值(而是将其插入另一个对象中)来伪造总体控制。有关实际获得对属性访问的完全控制的方法,请参见下面的getattribute()方法。

  • object. __getattribute__(* self name *)
    • 无条件调用以实现类实例的属性访问。如果该类还定义getattr(),则除非getattribute()显式调用它或引发AttributeError,否则不会调用后者。此方法应返回(计算出的)属性值或引发AttributeError异常。为了避免此方法中的无限递归,其实现应始终调用具有相同名称的 Base Class 方法以访问其所需的任何属性,例如object.__getattribute__(self, name)

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对对象有意义时,才应实现此目的。
  • object. __dir__(* self *)

    • 在对象上调用dir()时调用。必须返回一个序列。 dir()将返回的序列转换为列表并对其进行排序。

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

此方法应返回计算出的属性值或引发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)时。
  • Instance Binding

    • 如果绑定到对象实例,则a.x转换为调用:type(a).__dict__['x'].__get__(a, type(a))
  • Class Binding

    • 如果绑定到一个类,则A.x转换为调用:A.__dict__['x'].__get__(None, A)
  • Super Binding

    • 如果asuper的实例,则绑定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 __ *不适用于从“可变长度”内置类型(例如intbytestuple)派生的类。

  • 任何非字符串可迭代的对象都可以分配给* __ 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从包含此类参数的现有类继承来定制类创建过程。在以下示例中,MyClassMySubclass都是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)
  • class. __subclasscheck__(* self subclass *)

    • 如果* subclass 应该被视为 class *的(直接或间接)子类,则返回 true。如果定义,则调用以实现issubclass(subclass, class)

请注意,这些方法是在类的类型(元类)上查找的。它们不能在实际的类中定义为类方法。这与在实例上调用的特殊方法的查找一致,仅在这种情况下,实例本身是一个类。

See also

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 *)
    • 调用以实现内置函数len()。应该返回对象的长度,即整数>=0.此外,在 Boolean 上下文中,未定义bool()方法且len()方法返回零的对象也被视为 false。

CPython 实现细节: 在 CPython 中,长度最大为sys.maxsize。如果长度大于sys.maxsize,则某些要素(例如len())可能会升高OverflowError。为了防止pass真值测试提高OverflowError,对象必须定义bool()方法。

  • object. __length_hint__(* self *)
    • 调用以实现operator.length_hint()。应该返回对象的估计长度(可以大于或小于实际长度)。长度必须是>=0 的整数。返回值也可以是NotImplemented,其处理方式与__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 *)

    • 调用以实现对self[key]的赋值。与getitem()相同的 Comments。仅当对象支持键的值更改,或者可以添加新键的情况下,或如果元素可以替换的序列时,才应为 Map 实现。对于不正确的* key *值,应该引发与getitem()方法相同的 exception。
  • object. __delitem__(* self key *)

    • 调用以实现self[key]的删除。与getitem()相同的 Comments。如果对象支持删除键,则仅应针对 Map 实现;如果可以从序列中删除元素,则应仅对序列实现。对于不正确的* key *值,应该引发与getitem()方法相同的 exception。
  • object. __missing__(* self key *)

    • dict调用。当 key 不在字典中时,getitem()为 dict 子类实现self[key]
  • object. __iter__(* self *)

    • 当容器需要迭代器时,将调用此方法。此方法应返回一个新的迭代器对象,该对象可以遍历容器中的所有对象。对于 Map,它应该遍历容器的键。

迭代器对象也需要实现此方法;他们必须返回自己。有关迭代器对象的更多信息,请参见Iterator Types

  • object. __reversed__(* self *)
    • 内置reversed()调用(如果存在)以实现反向迭代。它应该返回一个新的迭代器对象,该对象以相反的 Sequences 遍历容器中的所有对象。

如果未提供reversed()方法,则内置reversed()将回退到使用序列协议(len()getitem())。支持序列协议的对象只有在提供比reversed()提供的实现效率更高的实现时,才应提供reversed()

成员资格测试运算符(innot 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 *)
    • 调用这些方法以实现二进制算术运算(+-*@///%divmod()pow()**<<>>&^|)。例如,要计算表达式x + y,其中* x *是具有add()方法的类的实例,则调用x.__add__(y)divmod()方法应等效于使用floordiv()mod();它不应与truediv()相关。请注意,如果要支持内置pow()函数的三元版本,则应将pow()定义为接受可选的第三个参数。

如果这些方法之一不支持使用提供的参数进行的操作,则应返回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 *)
    • 调用这些方法以实现具有反射的(交换的)操作数的二进制算术运算(+-*@///%divmod()pow()**<<>>&^|)。仅当左操作数不支持相应的操作[3]并且操作数是不同类型时,才调用这些函数。 [4]例如,要计算表达式x - y,其中* y 是具有rsub()方法的类的实例,如果x.__sub__(y)返回 NotImplemented *,则会调用y.__rsub__(x)

请注意,三 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子句中指定的目标(如果有)。
  • object. __exit__(* self exc_type exc_value traceback *)

    • 退出与此对象相关的运行时上下文。这些参数描述了导致退出上下文的异常。如果上下文无 exception 地退出,则所有三个参数均为None

如果提供了异常,并且该方法希望抑制该异常(即,防止其传播),则它应返回一个真值。否则,将在退出此方法后正常处理异常。

请注意,exit()个方法不应引发传入的异常。这是呼叫者的责任。

See also

  • PEP 343-“ with”语句

  • Python with语句的规范,背景和示例。

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()

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()返回值进行迭代时相同。
  • 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

  • [1]

    • 在某些情况下,在某些受控条件下,有可能更改对象的类型。但是,通常这不是一个好主意,因为如果处理不当,它可能会导致某些非常奇怪的行为。
  • [2]

  • [3]

    • 这里的“不支持”表示该类没有这样的方法,或者该方法返回NotImplemented。如果要强制回退到正确的操作数的反射方法,请不要将方法设置为None,这将具有显着阻止此类回退的相反效果。
  • [4]

    • 对于相同类型的操作数,假定如果非反射方法(例如add())失败,则不支持该操作,这就是为什么不调用反射方法的原因。