3. Data model

3.1. 对象,值和类型

对象是 Python 的数据抽象。 Python 程序中的所有数据都由对象或对象之间的关系表示。 (在某种意义上,并且按照冯·诺依曼的“存储程序计算机”模型,代码也由对象表示.)

每个对象都有一个标识,一个类型和一个值。创建对象后,其“身份”就永远不会改变;您可能会认为它是对象在内存中的地址。 'is'运算符比较两个对象的身份; id()函数返回一个表示其身份的整数(当前实现为其地址)。对象的* type 也不可更改。 [1]对象的类型确定该对象支持的操作(例如,“它是否有长度?”),并且还定义了该类型对象的可能值。 type()函数返回对象的类型(对象本身)。某些对象的可以更改。其值可以更改的对象被称为 mutable ;创建后其值不可更改的对象称为 immutable *。 (当更改可变对象的值时,包含对可变对象的引用的不可变容器对象的值可以更改;但是该容器仍被认为是不可变的,因为它所包含的对象的集合无法更改.因此,不可变性并不是严格意义上的与具有不变的值一样,它更加微妙.)对象的可变性由其类型决定;例如,数字,字符串和 Tuples 是不可变的,而字典和列表则是可变的。

从不显式销毁对象。但是,当它们变得不可访问时,它们可能会被垃圾回收。允许某个实现推迟或完全取消垃圾回收-只要没有收集到仍可到达的对象,垃圾回收的实现方式就取决于实现质量。

CPython 实现细节: CPython 当前使用带有循环计数垃圾的(可选)延迟检测的引用计数方案,该方案会在无法访问时立即收集大多数对象,但不能保证收集包含循环引用的垃圾。有关控制循环垃圾收集的信息,请参见gc模块的文档。其他实现的行为有所不同,CPython 可能会发生变化。当对象变得不可访问时,不要依赖它们的即时完成(例如:始终关闭文件)。

请注意,使用实现的跟踪或调试Function可能会使通常可以收集的对象保持活动状态。另请注意,使用'tryexcept'语句捕获异常可能会使对象保持活动状态。

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

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

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

3.2. 标准类型层次结构

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

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

  • None

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

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

    • 此类型具有单个值。有一个具有此值的对象。pass内置名称Ellipsis访问此对象。它用于指示切片中...语法的存在。它的真实价值是真实的。
  • numbers.Number

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

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

  • numbers.Integral

    • 这些代表整数 math 集合(正数和负数)中的元素。

整数有三种类型:

  • Plain integers

     - These represent numbers in the range \-2147483648 through 2147483647\. \(The range may be larger on machines with a larger natural word size, but not smaller\.\) When the result of an operation would fall outside this range, the result is normally returned as a long integer \(in some cases, the exception [OverflowError](library-exceptions.html#exceptions.OverflowError) is raised instead\)\. For the purpose of shift and mask operations, integers are assumed to have a binary, 2's complement notation using 32 or more bits, and hiding no bits from the user \(i\.e\., all 4294967296 different bit patterns correspond to different values\)\.
    
 - Long integers

   - These represent numbers in an unlimited range, subject to available \(virtual\) memory only\. For the purpose of shift and mask operations, a binary representation is assumed, and negative numbers are represented in a variant of 2's complement which gives the illusion of an infinite string of sign bits extending to the left\.
 - Booleans

   - 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 plain integers, 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

    • 这些将复数表示为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

     - The items of a string are characters\. There is no separate character type; a character is represented by a string of one item\. Characters represent \(at least\) 8\-bit bytes\. The built\-in functions [chr\(\)](library-functions.html#chr) and [ord\(\)](library-functions.html#ord) convert between characters and nonnegative integers representing the byte values\. Bytes with the values 0–127 usually represent the corresponding ASCII values, but the interpretation of values is up to the program\. The string data type is also used to represent arrays of bytes, e\.g\., to hold data read from a file\.
    

(在本机字符集不是 ASCII 的系统上,如果函数chr()ord()实现了 ASCII 和 EBCDIC 之间的 Map,并且字符串比较保留了 ASCIISequences,则字符串可以在其内部表示中使用 EBCDIC。或者也许有人可以提出更好的规则?)

 - Unicode

   - The items of a Unicode object are Unicode code units\. A Unicode code unit is represented by a Unicode object of one item and can hold either a 16\-bit or 32\-bit value representing a Unicode ordinal \(the maximum value for the ordinal is given in  `sys.maxunicode` , and depends on how Python is configured at compile time\)\. Surrogate pairs may be present in the Unicode object, and will be reported as two separate items\. The built\-in functions [unichr\(\)](library-functions.html#unichr) and [ord\(\)](library-functions.html#ord) convert between code units and nonnegative integers representing the Unicode ordinals as defined in the Unicode Standard 3\.0\. Conversion from and to other encodings are possible through the Unicode method  `encode()`  and the built\-in function [unicode\(\)](library-functions.html#unicode)\.
 - 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\.
  • 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-functions.html#bytearray) constructor\. Aside from being mutable \(and hence unhashable\), byte arrays otherwise provide the same interface and functionality as immutable bytes objects\.

扩展模块array提供了可变序列类型的其他示例。

  • 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),则可以互换使用它们来索引相同的字典条目。

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

扩展模块dbmgdbmbsddb提供了 Map 类型的其他示例。

  • Callable types

    • 这些是可以应用函数调用操作的类型(请参见Calls):
  • User-defined functions

    • 用户定义的Function对象由Function定义创建(请参见Function definitions)。应该使用包含与函数的形式参数列表相同数量的项的参数列表来调用它。

Special attributes:

AttributeMeaning
__doc__ func_doc该函数的文档字符串,或None(如果不可用)。Writable
name func_name函数名称Writable
__module__函数定义所在的模块的名称,如果不可用,则返回NoneWritable
__defaults__ func_defaults一个 Tuples,其中包含具有默认值的那些参数的默认参数值;如果没有参数具有默认值,则为NoneWritable
__code__ func_code表示已编译函数主体的代码对象。Writable
__globals__ func_globals对字典的引用,该字典包含函数的全局变量-定义函数的模块的全局命名空间。Read-only
dict func_dict支持任意Function属性的名称空间。Writable
__closure__ func_closureNone或包含该函数的自由变量的绑定的单元格 Tuples。Read-only

标记为“可写”的大多数属性都会检查分配值的类型。

在版本 2.4 中更改:func_name现在可写。

在 2.6 版中进行了更改:引入了双下划线属性__closure____code____defaults____globals__作为相应func_*属性的别名,以便与 Python 3 向前兼容。

函数对象还支持获取和设置任意属性,这些属性可以用于例如将元数据附加到函数。常规属性点符号用于获取和设置此类属性。 请注意,当前实现仅支持用户定义函数上的函数属性。将来可能会支持内置函数的函数属性.

可以从其代码对象中检索有关函数定义的其他信息。请参阅下面的内部类型说明。

  • User-defined methods

    • 用户定义的方法对象将类,类实例(或None)和任何可调用对象(通常是用户定义的函数)组合在一起。

特殊的只读属性:im_self是类实例对象,im_func是函数对象; im_classim_self的绑定方法类,或者是要求该方法使用非绑定方法的类; __doc__是方法的文档(与im_func.__doc__相同); name是方法名称(与im_func.__name__相同); __module__是在其中定义方法的模块的名称,或None(如果不可用)。

在版本 2.2 中更改:im_self用于引用定义该方法的类。

在 2.6 版中进行了更改:对于 Python 3 前向兼容性,im_func也可以用作__func__im_self也可以作为__self__

方法还支持访问(但不设置)基础函数对象上的任意函数属性。

如果某个类的属性是用户定义的函数对象,未绑定的用户定义的方法对象或类的方法对象,则在获取类的属性时(可能pass该类的实例)可以创建用户定义的方法对象。当该属性是用户定义的方法对象时,仅当要从中检索该属性的类与原始方法对象中存储的类相同或派生出类时,才创建新的方法对象;否则,将按原样使用原始方法对象。

pass从类中检索用户定义的函数对象创建用户定义的方法对象时,其im_self属性为None,并且该方法对象被认为是未绑定的。当pass某个类的实例之一从类中检索用户定义的函数对象而创建一个对象时,其im_self属性是该实例,并且该方法对象称为绑定对象。无论哪种情况,新方法的im_class属性都是从其进行检索的类,而其im_func属性是原始函数对象。

当pass从类或实例中检索另一个方法对象创建用户定义的方法对象时,其行为与Function对象相同,只是新实例的im_func属性不是原始方法对象,而是其im_func属性。 。

pass从类或实例中检索类方法对象创建用户定义的方法对象时,其im_self属性是类本身,而其im_func属性是该类方法下的函数对象。

调用未绑定的用户定义的方法对象时,将调用基础函数(im_func),并具有以下限制:第一个参数必须是适当类(im_class)或其派生类的实例。

调用绑定的用户定义的方法对象时,将调用基础函数(im_func),并将类实例(im_self)插入参数列表的前面。例如,当C是包含函数f()的定义的类,并且xC的实例时,调用x.f(1)等效于调用C.f(x, 1)

当从类方法对象派生用户定义的方法对象时,存储在im_self中的“类实例”实际上将是类本身,因此调用x.f(1)C.f(1)等效于调用f(C,1),其中f是基础函数。

请注意,每次从类或实例检索属性时,都会发生从函数对象到(未绑定或绑定)方法对象的转换。在某些情况下,卓有成效的优化是将属性分配给局部变量并调用该局部变量。还要注意,这种转换仅发生在用户定义的函数上。其他可调用对象(以及所有不可调用对象)无需进行转换即可检索。同样重要的是要注意,作为类实例属性的用户定义函数不会转换为绑定方法。 发生在函数是类的属性时。

  • Generator functions

    • 使用yield语句(请参阅yield语句)的函数或方法称为生成器函数。调用此函数时,始终会返回一个迭代器对象,该对象可用于执行函数的主体:调用迭代器的next()方法将导致该函数执行,直到使用yield语句提供值为止。当函数执行return语句或结束结尾时,将引发StopIteration异常,并且迭代器将到达要返回的值集的结尾。
  • 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 *表示的对象。
  • Class Types

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

    • 类对象描述如下。调用类对象时,将创建并返回一个新的类实例(也将在下面进行描述)。这意味着将调用该类的init()方法(如果有)。任何参数都将传递给init()方法。如果没有init()方法,则必须在不带参数的情况下调用该类。
  • Class instances

    • 类实例如下所述。仅当类具有call()方法时,类实例才可调用; x(arguments)x.__call__(arguments)的简写。
  • Modules

    • 模块是passimport语句导入的(请参见import 语句部分)。模块对象具有由字典对象(这是模块中定义的函数的 func_globals 属性引用的字典)实现的名称空间。将属性引用转换为此字典中的查找,例如m.x等效于m.__dict__["x"]。模块对象不包含用于初始化模块的代码对象(因为一旦完成初始化就不需要它)。

属性分配会更新模块的名称空间字典,例如m.x = 1等效于m.__dict__["x"] = 1

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

CPython 实现细节: 由于 CPython 清除模块词典的方式,即使模块仍具有实时引用,当模块超出范围时,模块词典也会被清除。为避免这种情况,请复制字典或在直接使用其字典时保留模块。

sched 义(可写)属性:__name__是模块的名称; __doc__是模块的文档字符串,或None(如果不可用); __file__是从中加载模块的文件的路径名(如果它是从文件加载的)。静态链接到解释器的 C 模块不提供__file__属性。对于从共享库动态加载的扩展模块,它是共享库文件的路径名。

  • Classes

    • 类类型(新样式类)和类对象(旧样式/经典类)通常都是由类定义创建的(请参阅Class definitions)。类具有由字典对象实现的名称空间。类属性引用被翻译成该字典中的查询,例如C.x被翻译成C.__dict__["x"](尽管特别是对于新式类,有许多钩子允许使用其他方式查找属性)。当在此处找不到属性名称时,将 continue 在 Base Class 中搜索属性。对于旧类,搜索是从深度优先,从左到右,从 Base Class 列表的出现 Sequences 开始。new-style类使用更复杂的 C3 方法解析 Sequences,即使在“钻石”继承结构(其中有多个继承路径返回到共同祖先)的情况下,该行为也能正确运行。新样式类使用的 C3 MRO 的其他详细信息可以在 2.3 版本https://www.python.org/download/releases/2.3/mro/随附的文档中找到。

当类属性引用(例如C类)产生用户定义的函数对象或未绑定的用户定义的方法对象(其关联的类是C或其 Base Class 之一)时,它将转换为未绑定的用户定义im_class属性为C的方法对象。当产生类方法对象时,它将转换为绑定的用户定义方法对象,该对象的im_self属性为C。当产生静态方法对象时,它将转换为由静态方法对象包装的对象。有关从类检索的属性可能与实际包含在其dict中的属性不同的另一种方式,请参见Implementing Descriptors节(请注意,仅新式类支持 Descriptors)。

类属性分配更新类的字典,而不更新 Base Class 的字典。

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

特殊属性:name是类名; __module__是定义类的模块名称; dict是包含类名称空间的字典; bases是一个包含 Base Class 的 Tuples(可能为空或单例),按照 Base Class 在 Base Class 列表中的出现 Sequences 排列; __doc__是该类的文档字符串,或者None(如果未定义)。

  • Class instances

    • pass调用类对象来创建类实例(请参见上文)。一个类实例具有一个实现为字典的名称空间,这是搜索属性引用的第一位。如果在该处找不到属性,并且实例的类具有该名称的属性,则 continue 使用类属性进行搜索。如果发现一个类属性是一个用户定义的函数对象或一个未绑定的用户定义的方法对象,其关联的类是为其启动属性引用的实例的类(称为C)或其基础之一,则它转换为绑定的用户定义方法对象,该对象的im_class属性为Cim_self属性为实例。静态方法和类方法对象也将转换,就好像它们是从C类中检索的一样;请参见上文“类别”下的内容。有关pass其实例检索的类的属性可能与实际存储在该类dict中的对象不同的另一种方式,请参见Implementing Descriptors部分。如果未找到 class 属性,并且对象的类具有getattr()方法,则调用该方法以满足查找。

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

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

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

  • Files

    • 文件对象代表一个打开的文件。文件对象是由内置的open()函数以及套接字对象的os.popen()os.fdopen()makefile()方法(以及可能由扩展模块提供的其他函数或方法)创建的。将对象sys.stdinsys.stdoutsys.stderr初始化为与解释器的标准 Importing,输出和错误流相对应的文件对象。有关文件对象的完整文档,请参见File Objects
  • Internal types

    • 解释器内部使用的一些类型向用户公开。它们的定义可能会随将来版本的解释器而变化,但是为了完整起见在此提及它们。
  • Code objects

    • 代码对象表示字节编译的可执行 Python 代码或bytecode。代码对象和Function对象之间的区别在于,Function对象包含对函数全局变量(定义该模块的模块)的显式引用,而代码对象则不包含上下文。默认参数值也存储在函数对象中,而不存储在代码对象中(因为它们表示运行时计算出的值)。与函数对象不同,代码对象是不可变的,并且不包含(直接或间接)可变对象的引用。

特殊的只读属性:co_name给出函数名称; co_argcount是位置参数(包括具有默认值的参数)的数量; 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_restricted是指示Function是否在受限执行模式下执行的标志; f_lasti给出精确的指令(这是代码对象的字节码字符串的索引)。

特殊的可写属性:f_trace(如果不是None)是在每个源代码行的开头调用的函数(调试器使用该函数); f_exc_typef_exc_valuef_exc_traceback表示在父帧中引发的最后一个异常,前提是当前帧中曾引发过另一个异常(在所有其他情况下均为None); f_lineno是该帧的当前行号-从跟踪函数中写入该行号将跳至给定的行(仅适用于最底部的帧)。调试器可以pass写入 f_lineno 来实现 Jump 命令(也称为 Set Next 语句)。

  • Traceback objects

    • traceback 对象表示异常的堆栈跟踪。发生异常时创建回溯对象。当搜索异常处理程序展开执行堆栈时,在每个展开级别上,都会在当前回溯的前面插入一个回溯对象。Importing 异常处理程序后,堆栈跟踪可用于程序。 (请参见try 语句。)它可以作为sys.exc_traceback以及sys.exc_info()返回的 Tuples 的第三项来访问。后者是首选接口,因为当程序使用多个线程时它可以正常工作。当程序不包含合适的处理程序时,堆栈跟踪将被写入(格式正确)到标准错误流中。如果解释器是交互式的,则它也以sys.last_traceback的形式提供给用户。

特殊的只读属性:tb_next是堆栈跟踪中的下一层(朝向发生异常的帧),或None(如果没有下一层); tb_frame指向当前级别的执行框架; tb_lineno给出发生异常的行号; tb_lasti表示精确指令。如果异常发生在try语句中,没有匹配的 except 子句或带有 finally 子句,则回溯中的行号和最后一条指令可能与其框架对象的行号不同。

  • Slice objects

    • 当使用“扩展切片语法”时,切片对象用于表示切片。这是一个使用两个冒号的切片,或者是多个以逗号分隔的切片或椭圆,例如a[i:j:step]a[i:j, k:l]a[..., i:j]。它们也由内置的slice()函数创建。

特殊的只读属性:start是下限; stop是上限; step是步长值;如果Ellipsis,则每个为None。这些属性可以具有任何类型。

切片对象支持一种方法:

  • slice. indices(* self length )

    -此方法采用单个整数参数
    length ,并计算有关切片对象(如果应用于 length 项目序列)将描述的扩展切片的信息。它返回三个整数的 Tuples。它们分别是 start stop 索引以及切片的 step *或步幅。丢失或越界索引的处理方式与常规切片一致。

2.3 版的新Function。

  • 静态方法对象

    • 静态方法对象提供了一种克服Function对象向上述方法对象的转换的方法。静态方法对象是任何其他对象(通常是用户定义的方法对象)的包装。从类或类实例中检索静态方法对象时,实际返回的对象是包装的对象,无需进行任何进一步的转换。静态方法对象本身不是可调用的,尽管它们通常包装的对象是可调用的。静态方法对象由内置的staticmethod()构造函数创建。
  • 类方法对象

    • 类方法对象就像静态方法对象一样,是另一个对象的包装,它更改了从类和类实例检索该对象的方式。上面在“用户定义的方法”下描述了此类检索时类方法对象的行为。类方法对象是由内置的classmethod()构造函数创建的。

3.3. New-style and classic classes

类和实例有两种风格:旧样式(或经典样式)和新样式。

在 Python 2.1 之前,class的概念与type的概念无关,而旧式类是唯一可用的样式。对于老式类,语句x.__class__提供* x *的类,但type(x)始终为<type 'instance'>。这反映了一个事实,即所有旧式实例(独立于其类)均使用称为instance的单个内置类型实现。

在 Python 2.2 中引入了新的类,以统一classtype的概念。new-style类只是用户定义的类型,不多也不少。如果* x *是新样式类的实例,则type(x)通常与x.__class__相同(尽管不能保证–允许新样式类实例覆盖x.__class__返回的值)。

引入new-style类的主要动机是提供具有完整元模型的统Pair象模型。它还具有许多实际的好处,例如可以对大多数内置类型进行子类化,或者可以引入“Descriptors”来启用计算属性。

出于兼容性原因,默认情况下,类仍为旧样式。pass将另一个新样式类(即一种类型)指定为父类来创建新样式类,如果不需要其他父类,则可以指定“顶级类型” object。新样式类的行为与旧样式类的行为不同,除了type()返回的内容外,还有许多重要的细节。其中一些更改是新对象模型的基础,例如调用特殊方法的方式。其他是出于兼容性考虑而无法实现的“修复程序”,例如在多重继承的情况下的方法解析 Sequences。

尽管本手册旨在全面介绍 Python 的类机制,但在涉及新样式类的某些领域可能仍然缺少。有关其他信息的来源,请参见https://www.python.org/doc/newstyle/

Python 3 中删除了旧式类,仅保留了新式类。

3.4. 特殊方法名称

一个类可以pass定义具有特殊名称的方法,来实现由特殊语法调用的某些操作(例如算术运算或下标和切片)。这是 Python 的运算符重载的方法,允许类针对语言运算符定义自己的行为。例如,如果一个类定义了一个名为getitem()的方法,并且x是该类的实例,则x[i]大致等效于x.__getitem__(i)(对于旧样式类)和type(x).__getitem__(x, i)(对于新样式类)。除非另有说明,否则当未定义适当的方法(通常为AttributeErrorTypeError)时,try执行操作会引发异常。

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

3.4.1. 基本定制

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

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

如果new()返回* cls 的实例,则将像__init__(self[, ...])一样调用新实例的init()方法,其中 self *是新实例,其余参数与传递给new()的参数相同。

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

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

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

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

  • object. __del__(* self *)
    • 在实例即将销毁时调用。这也称为析构函数。如果 Base Class 具有del()方法,则派生类的del()方法(如果有)必须显式调用它,以确保正确删除实例的 Base Class 部分。请注意,del()方法有可能(尽管不建议使用!)pass创建对实例的新引用来推迟实例的销毁。然后,在删除此新引用时,可以在以后的时间调用它。不能保证为解释器退出时仍然存在的对象调用del()方法。

Note

del x不会直接调用x.__del__()-前者会将x的引用计数减一,而后者仅在x的引用计数达到零时才调用。可能会阻止对象的引用计数变为零的一些常见情况包括:对象之间的循环引用(例如,双向链接列表或具有父和子指针的树数据结构);对捕获异常的函数的堆栈框架上的对象的引用(存储在sys.exc_traceback中的回溯使堆栈框架保持活动状态);或对在交互式模式下引发未处理异常的堆栈框架上对象的引用(存储在sys.last_traceback中的回溯使堆栈框架保持活动状态)。第一种情况只能pass明确 break 循环来解决。pass将None存储在sys.exc_tracebacksys.last_traceback中,可以解决后两种情况。启用选项循环检测器(默认情况下处于启用状态)时,将检测为垃圾的循环引用,但只有在不涉及 Python 级别的del()方法的情况下,才能对其进行清理。有关循环检测器如何处理del()方法的更多信息,尤其是garbage值的说明,请参阅gc模块的文档。

Warning

由于调用del()方法的危险情况,在执行过程中发生的异常将被忽略,并向sys.stderr打印警告。同样,当响应于模块被删除而调用del()时(例如,在执行程序时),del()方法引用的其他全局变量可能已经被删除或正在拆除中(例如,import 机械)关闭)。因此,del()方法应该执行维护外部不变式所需的绝对最小值。从版本 1.5 开始,Python 保证在删除其他全局变量之前,将从其下划线开头的全局变量从其模块中删除。如果不存在对此类全局变量的其他引用,则这可能有助于确保在调用del()方法时导入的模块仍然可用。

另请参见-R命令行选项。

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

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

  • object. __str__(* self *)
    • str()内置函数和print语句调用以计算对象的“非正式”字符串表示形式。这与repr()的不同之处在于,它不一定是有效的 Python 表达式:可以使用更方便或更简洁的表示形式。返回值必须是一个字符串对象。
  • object. __lt__(* self other *)
  • object. __le__(* self other *)
  • object. __eq__(* self other *)
  • object. __ne__(* self other *)
  • object. __gt__(* self other *)
  • object. __ge__(* self other *)
    • 2.1 版中的新Function。

这些是所谓的“丰富比较”方法,它们优先于下面的cmp()用作比较运算符。运算符和方法名称之间的对应关系如下:x<y调用x.__lt__(y)x<=y调用x.__le__(y)x==y调用x.__eq__(y)x!=yx<>y调用x.__ne__(y)x>y调用x.__gt__(y)x>=y调用x.__ge__(y)

如果丰富的比较方法未实现给定参数对的操作,则可能返回单例NotImplemented。按照惯例,返回FalseTrue以进行成功比较。但是,这些方法可以返回任何值,因此,如果在布尔上下文中使用比较运算符(例如,在if语句的条件下),Python 将在该值上调用bool()以确定结果是 true 还是 false。

比较运算符之间没有隐含的关系。 x==y的 Truth 并不意味着x!=y为假。因此,在定义eq()时,还应定义ne(),以便操作员将按预期方式工作。有关创建hashable对象(支持自定义比较操作并可用作字典键)的一些重要说明,请参见hash()上的段落。

这些方法没有交换参数版本(当左参数不支持该操作但右参数支持该操作时使用); lt()gt()是彼此的反射,le()ge()是彼此的反射,而eq()ne()是它们自己的反射。

丰富比较方法的论点永远不会被强迫。

要从单个 root 操作自动生成排序操作,请参见functools.total_ordering()

  • object. __cmp__(* self other *)
    • 如果未定义丰富比较(请参见上文),则由比较操作调用。如果self < other则应返回负整数,如果self == other则应返回零,如果self > other则应返回正整数。如果未定义cmp()eq()ne()操作,则按对象标识(“地址”)比较类实例。另请参见hash()的说明,以获取有关创建hashable对象的一些重要说明,这些对象支持自定义比较操作并可用作字典键。 (注意:自 Python 1.5 开始,已消除了cmp()不传播异常的限制。)
  • object. __rcmp__(* self other *)

    • 在版本 2.1 中更改:不再受支持。
  • object. __hash__(* self *)

    • 由内置函数hash()调用,用于对哈希集合的成员(包括setfrozensetdict)进行操作。 hash()应该返回一个整数。唯一需要的属性是比较相等的对象具有相同的哈希值。建议将对象的组成部分的哈希值混合在一起,方法是将它们打包成一个 Tuples 并哈希该 Tuples,从而在对象比较中也发挥作用。例:
def __hash__(self):
    return hash((self.name, self.nick, self.color))

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

用户定义的类默认情况下具有cmp()hash()方法。使用它们,所有对象比较不相等(除了它们本身),并且x.__hash__()返回从id(x)派生的结果。

从父类继承hash()方法但更改cmp()eq()的含义,以使返回的哈希值不再合适的类(例如,pass切换到基于值的相等性概念,而不是默认的基于身份的相等性)的类可以显式地pass在类定义中设置__hash__ = None来将自己标记为不可散列。这样做意味着不仅在程序try检索其哈希值时,该类的实例将引发一个适当的TypeError,而且在检查isinstance(obj, collections.Hashable)时也将它们正确标识为不可哈希(与定义自己的hash()以显式引发TypeError的类不同)。 。

在版本 2.5 中进行了更改:hash()现在也可能返回一个长整数对象;然后,从该对象的哈希中得出 32 位整数。

在 2.6 版中进行了更改:现在可以将hash设置为None,以将类的实例显式标记为不可散列。

  • object. __nonzero__(* self *)
    • 调用以实现真值测试和内置操作bool();应该返回FalseTrue或它们等效的整数01。如果未定义此方法,则调用len()(如果已定义),并且如果其结果为非零,则认为该对象为 true。如果一个类既未定义len()也未定义nonzero(),则其所有实例均被视为 true。
  • object. __unicode__(* self *)
    • 调用以实现unicode()内置;应该返回一个 Unicode 对象。未定义此方法时,将try进行字符串转换,并使用系统默认编码将字符串转换的结果转换为 Unicode。

3.4.2. 自定义属性访问

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

  • object. __getattr__(* self name *)
    • 当属性查找未在通常位置找到该属性时调用(即,它不是实例属性,也不是在self的类树中找到该属性)。 name是属性名称。此方法应返回(计算出的)属性值或引发AttributeError异常。

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

  • object. __setattr__(* self name value *)
    • try分配属性时调用。这被称为而不是常规机制(即,将值存储在实例字典中)。 * name 是属性名称, value *是要为其分配的值。

如果setattr()要分配给实例属性,则不应简单地执行self.name = value -这将导致对其自身的递归调用。而是应将值插入实例属性的字典中,例如self.__dict__[name] = value。对于new-style类,应该访问具有相同名称的 Base Class 方法,例如object.__setattr__(self, name, value),而不是访问实例字典。

  • object. __delattr__(* self name *)
    • 类似于setattr(),但用于属性删除而不是分配。仅当del obj.name对对象有意义时,才应实现此目的。

3.4.2.1. new-style类的更多属性访问

以下方法仅适用于new-style类。

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

Note

查找特殊方法时,由于pass语言语法或内置函数进行隐式调用的结果,仍可能会绕过此方法。参见new-style类的特殊方法查找

3.4.2.2. 实现 Descriptors

以下方法仅在包含该方法的类的实例(所谓的* descriptor 类)出现在 owner *类中时(Descriptors 必须位于所有者的类字典或类字典中的其中一个对象中)时适用它的 parent)。在下面的示例中,“属性”是指名称是所有者类'dict中的属性的键的属性。

  • object. __get__(* self instance owner *)

    • 调用以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问)。 * owner 始终是所有者类,而 instance 是pass其访问属性的实例,当pass owner *访问属性时是None。此方法应返回(计算出的)属性值或引发AttributeError异常。
  • object. __set__(* self instance value *)

    • 调用以将所有者类的实例* instance 上的属性设置为新值 value *。
  • object. __delete__(* self instance *)

    • 调用以删除所有者类的实例* instance *上的属性。

3.4.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 方法以及如何调用它们。请注意,仅对新样式对象或类(子类object()type()的子类)调用 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.4.2.4. slots

默认情况下,新旧类的实例都具有用于属性存储的字典。这浪费了具有很少实例变量的对象的空间。创建大量实例时,空间消耗会变得非常大。

可以pass在新的类定义中定义* __ slots __ *来覆盖默认值。 * __ slots __ 语句采用一系列实例变量,并在每个实例中仅保留足够的空间来容纳每个变量的值。因为未为每个实例创建 __ dict __ *,所以节省了空间。

  • __slots__
    • 可以为该类变量分配一个字符串,可迭代的字符串或具有实例使用的变量名称的字符串序列。如果在新类中定义,则* __ slots __ 为语句的变量保留空间,并防止为每个实例自动创建 __ dict __ __ weakref __ *。

2.2 版中的新Function。

使用* __ slots __ *的注意事项

  • 从没有* __ slots __ 的类继承时,该类的 __ dict __ 属性将始终可访问,因此子类中的 __ slots __ *定义是没有意义的。

  • 如果没有* __ dict __ 变量,则无法为实例分配 __ slots __ *定义中未列出的新变量。try分配给未列出的变量名会引发AttributeError。如果需要动态分配新变量,则在__slots __ *语句中的字符串序列中添加'__dict__'

在版本 2.3 中进行了更改:以前,在 slots __ *语句中添加'__dict__'将无法分配实例变量名称序列中未特别列出的新属性。

  • 对于每个实例,如果没有* __ weakref __ 变量,则定义 __ slots __ *的类将不支持对其实例的弱引用。如果需要弱引用支持,则在__slots __ *语句中的字符串序列中添加'__weakref__'

在版本 2.3 中进行了更改:以前,在 slots __ *语句中添加'__weakref__'不会启用对弱引用的支持。

    • __ slots __ 在类级别pass为每个变量名称创建 Descriptors(Implementing Descriptors)实现。结果,类属性不能用于为 __ slots __ *定义的实例变量设置默认值;否则,class 属性将覆盖 Descriptors 分配。
    • __ slots __ 语句的操作仅限于定义该语句的类。结果,子类将具有 __ dict __ ,除非它们也定义了 __ slots __ (必须仅包含任何 additional *插槽的名称)。
  • 如果一个类定义了也在 Base Class 中定义的插槽,则无法访问由 Base Class 插槽定义的实例变量(除非直接从 Base Class 中获取其 Descriptors)。这使程序的含义不确定。将来可能会添加检查以防止这种情况。

  • 非空* __ slots __ *不适用于从“可变长度”内置类型(例如longstrtuple)派生的类。

  • 任何非字符串可迭代的对象都可以分配给* __ slots __ *。也可以使用 Map。但是,将来,可能会为每个键对应的值分配特殊含义。

    • __ class __ 分配仅在两个类具有相同的 __ slots __ *时才有效。

在 2.6 版中进行了更改:以前,如果新类或旧类具有* __ slots __ ,则 __ class __ *分配会引发错误。

3.4.3. 定制类创建

默认情况下,使用type()构造新样式的类。将类定义读入单独的命名空间,并将类名的值绑定到type(name, bases, dict)的结果。

读取类定义时,如果定义了* __ metaclass __ *,则将调用分配给它的可调用对象,而不是type()。这允许编写监视或更改类创建过程的类或函数:

  • 在创建类之前修改类字典。

  • 返回另一个类的实例–本质上执行工厂函数的角色。

这些步骤必须在元类的new()方法中执行-然后可以从此方法中调用type.__new__()以创建具有不同属性的类。本示例在创建类之前将新元素添加到类字典中:

class metacls(type):
    def __new__(mcs, name, bases, dict):
        dict['foo'] = 'metacls was here'
        return type.__new__(mcs, name, bases, dict)

当然,您也可以覆盖其他类方法(或添加新方法)。例如,在元类中定义自定义call()方法可在调用该类时允许自定义行为,例如并不总是创建一个新实例。

  • __metaclass__
    • 此变量可以是namebasesdict的任何可调用接受参数。创建类时,将使用 callable 而不是内置的type()

2.2 版中的新Function。

适当的元类由以下优先级规则确定:

  • 如果dict['__metaclass__']存在,则使用它。

  • 否则,如果至少有一个 Base Class,则使用其元类(这将首先查找* __ class __ *属性,如果未找到,则使用其类型)。

  • 否则,如果存在名为__metaclass_的全局变量,则将使用它。

  • 否则,将使用旧的经典元类(types.ClassType)。

元类的潜在用途是无限的。已经探索了一些想法,包括日志记录,接口检查,自动委派,自动属性创建,代理,框架和自动资源锁定/同步。

3.4.4. 自定义实例和子类检查

2.6 版的新Function。

以下方法用于覆盖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.4.5. 模拟可调用对象

  • object. __call__(* self * [,* args ... *])
    • 当实例被“调用”为函数时调用;如果定义了此方法,则x(arg1, arg2, ...)x.__call__(arg1, arg2, ...)的简写。

3.4.6. 模拟容器类型

可以定义以下方法来实现容器对象。容器通常是序列(例如列表或 Tuples)或 Map(例如字典),但也可以表示其他容器。第一组方法用于仿真序列或仿真 Map。区别在于,对于序列,允许的键应为整数* k ,其中0 <= k < N为整数,其中 N *是序列的长度,或者是切片对象,它们定义项的范围。 (为了向后兼容,还可以定义方法getslice()(请参见下文)以处理简单但不扩展的切片。)还建议 Map 提供方法keys()values()items()has_key()get()clear()setdefault()iterkeys()itervalues()iteritems()pop()popitem()copy()update()的行为类似于 Python 的标准字典对象。 UserDict模块提供DictMixin类,以帮助从getitem()setitem()delitem()keys()的基础集中创建这些方法。可变序列应提供append()count()index()extend()insert()pop()remove()reverse()sort()的方法,例如 Python 标准列表对象。最后,序列类型应pass定义以下所述的方法add()radd()iadd()mul()rmul()imul()来实现加法(表示串联)和乘法(表示重复);他们不应定义coerce()或其他数字运算符。建议 Map 和序列都实现contains()方法,以允许有效使用in运算符。对于 Map,in应该等效于has_key();对于序列,它应该搜索值。进一步建议 Map 和序列都实现iter()方法,以允许pass容器进行有效的迭代。对于 Map,iter()应该与iterkeys()相同;对于序列,它应该遍历值。

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

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

  • 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,它应遍历容器的键,并且还应作为方法iterkeys()提供。

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

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

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

2.6 版的新Function。

成员资格测试运算符(innot in)通常实现为序列的迭代。但是,容器对象可以为以下特殊方法提供更有效的实现,这也不要求对象是序列。

  • object. __contains__(* self item *)
    • 要求实施成员资格测试操作员。如果* item self *中,则应返回 true,否则返回 false。对于 Map 对象,应考虑 Map 的键而不是值或键-项对。

对于未定义contains()的对象,成员资格测试首先passiter()try迭代,然后passgetitem()try旧的序列迭代协议,请参见语言参考中的本节

3.4.7. 模拟序列类型的其他方法

可以定义以下可选方法来进一步模拟序列对象。不可变序列方法最多只能定义getslice();可变序列可以定义所有三种方法。

  • object. __getslice__(* self i j *)
    • 从 2.0 版开始不推荐使用:支持将切片对象用作getitem()方法的参数。 (但是,CPython 中的内置类型当前仍实现getslice()。因此,在实现切片时必须在派生类中重写它。)

调用以实现self[i:j]的评估。返回的对象应该与* self 具有相同的类型。请注意,切片表达式中丢失的 i j *分别被零或sys.maxsize代替。如果在切片中使用负索引,则将序列的长度添加到该索引。如果实例未实现len()方法,则引发AttributeError。不能保证以此方式调整的索引仍然不是负数。大于序列长度的索引不会被修改。如果未找到getslice(),则会创建一个 slice 对象,并将其传递给getitem()

  • object. __setslice__(* self i j sequence *)
    • 调用以实现对self[i:j]的分配。 * i j *的 Comments 与getslice()相同。

不建议使用此方法。如果未找到setslice(),或者对于self[i:j:k]形式的扩展切片,将创建一个切片对象,并将其传递给setitem(),而不是调用setslice()

  • object. __delslice__(* self i j *)
    • 调用以实现self[i:j]的删除。 * i j *的 Comments 与getslice()相同。不建议使用此方法。如果未找到delslice(),或者对于形式为self[i:j:k]的扩展切片,将创建一个切片对象,并将其传递给delitem(),而不是调用delslice()

请注意,只有在使用带有单个冒号的单个切片并且 slice 方法可用时,才调用这些方法。对于涉及扩展切片符号或没有切片方法的切片操作,以切片对象作为参数调用getitem()setitem()delitem()

以下示例演示如何使您的程序或模块与 Python 的早期版本兼容(假设方法getitem()setitem()delitem()支持切片对象作为参数):

class MyClass:
    ...
    def __getitem__(self, index):
        ...
    def __setitem__(self, index, value):
        ...
    def __delitem__(self, index):
        ...

    if sys.version_info < (2, 0):
        # They won't be defined if version is at least 2.0 final

        def __getslice__(self, i, j):
            return self[max(0, i):max(0, j):]
        def __setslice__(self, i, j, seq):
            self[max(0, i):max(0, j):] = seq
        def __delslice__(self, i, j):
            del self[max(0, i):max(0, j):]
    ...

注意对max()的呼叫;这些是必需的,因为在调用__*slice__()方法之前要处理负索引。当使用负索引时,__*item__()方法按提供的方式接收它们,但是__*slice__()方法获得索引值的“煮熟”形式。对于每个负索引值,在调用方法之前将序列的长度添加到索引中(这可能仍会导致负索引);这是pass内置序列类型对负索引的常规处理,并且__*item__()方法也有望实现这一点。但是,由于他们应该已经在执行此操作,因此无法传递负索引。在将它们传递给__*item__()方法之前,必须将它们限制在序列的范围内。方便地调用max(0, i)返回正确的值。

3.4.8. 模拟数值类型

可以定义以下方法来模拟数字对象。与未实现的特定种类的数字不支持的操作相对应的方法(例如,非整数的按位运算)应保持未定义状态。

  • object. __add__(* self other *)
  • object. __sub__(* self other *)
  • object. __mul__(* 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. __div__(* self other *)

  • object. __truediv__(* self other *)

    • pass这些方法可实现除法运算符(/)。 __future__.division有效时使用truediv()方法,否则使用div()。如果仅定义这两种方法之一,则该对象将不支持在备用上下文中进行除法; TypeError将被提高。
  • object. __radd__(* self other *)

  • object. __rsub__(* self other *)

  • object. __rmul__(* self other *)

  • object. __rdiv__(* self other *)

  • object. __rtruediv__(* self other *)

  • object. __rfloordiv__(* self other *)

  • object. __rmod__(* self other *)

  • object. __rdivmod__(* self other *)

  • object. __rpow__(* self other *)

  • object. __rlshift__(* self other *)

  • object. __rrshift__(* self other *)

  • object. __rand__(* self other *)

  • object. __rxor__(* self other *)

  • object. __ror__(* self other *)

    • 调用这些方法以实现具有反射的(交换的)操作数的二进制算术运算(+-*/%divmod()pow()**<<>>&^|)。仅当左操作数不支持相应的操作且操作数是不同类型时,才调用这些函数。 [2]例如,要计算表达式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. __idiv__(* 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 += y,其中 x 是具有iadd()方法的类的实例,则调用x.__iadd__(y)。如果 x *是未定义iadd()方法的类的实例,则与x + y的求值一样,将考虑x.__add__(y)y.__radd__(x)
  • object. __neg__(* self *)

  • object. __pos__(* self *)

  • object. __abs__(* self *)

  • object. __invert__(* self *)

    • 调用以实现一元算术运算(-+abs()~)。
  • object. __complex__(* self *)
  • object. __int__(* self *)
  • object. __long__(* self *)
  • object. __float__(* self *)
  • object. __oct__(* self *)
  • object. __hex__(* self *)
    • 调用以实现内置函数oct()hex()。应该返回一个字符串值。
  • object. __index__(* self *)
    • 调用以实现operator.index()。每当 Python 需要整数对象时(例如在切片中),也会调用此方法。必须返回一个整数(int 或 long)。

2.5 版的新Function。

  • object. __coerce__(* self other *)
    • 调用以实现“混合模式”数字算法。应该返回一个包含* self other *的 2Tuples(转换为普通数字类型),或者返回None(如果无法进行转换)。当通用类型是other的类型时,返回None就足够了,因为解释器还将要求另一个对象try强制转换(但是有时,如果不能更改其他类型的实现,则对在此转换为其他类型)。 NotImplemented的返回值等效于None的返回值。

3.4.9. 强制规则

本部分用于记录强制性规则。随着语言的 Developing,强制规则变得难以精确记录。记录一个特定实现的一个版本的Function是不可取的。相反,这里有一些有关胁迫的非正式准则。在 Python 3 中,将不支持强制转换。

  • 如果%运算符的左操作数是字符串或 Unicode 对象,则不进行强制转换,而是调用字符串格式设置操作。

  • 不再建议定义强制操作。未定义强制类型的混合模式操作会将原始参数传递给该操作。

  • new-style类(从object派生的类)从不调用coerce()方法来响应二进制运算符; coerce()唯一的调用时间是在调用内置函数coerce()时。

  • 在大多数情况下,返回NotImplemented的运算符都将与未执行的运算符相同。

  • 下面,__op__()__rop__()用来表示与运算符相对应的通用方法名称; __iop__()用于相应的就地运算符。例如,对于运算符“ +”,add()radd()用于二进制运算符的左右变体,而iadd()用于就地变体。

  • 对于对象* x y *,首先tryx.__op__(y)。如果未实现或返回NotImplemented,则tryy.__rop__(x)。如果也未实现或返回NotImplemented,则会引发TypeError异常。但请参见以下异常:

  • 上一项的 exception:如果左操作数是内置类型或新样式类的实例,而右操作数是该类型或类的适当子类的实例,并且覆盖基数的__rop__()方法,则在左操作数的__op__()方法之前*,先try右操作数的__rop__()方法。

这样做是为了使子类可以完全覆盖二进制运算符。否则,左操作数的__op__()方法将始终接受右操作数:当期望给定类的实例时,该类的子类的实例总是可接受的。

  • 当任何一个操作数类型都定义了强制时,将在调用该类型的__op__()__rop__()方法之前调用此强制,但不会更早。如果强制返回了调用强制的操作数的其他类型的对象,则使用新对象重做部分过程。

  • 当使用就地运算符(如“ +=”)时,如果左操作数实现__iop__(),则无需任何强制即可调用它。当操作退回到__op__()和/或__rop__()时,将应用常规强制规则。

  • x + y中,如果* x *是实现序列串联的序列,则会调用序列串联。

  • x * y中,如果一个操作数是实现序列重复的序列,而另一个是整数(intlong),则调用序列重复。

  • 丰富的比较(由方法eq()等实现)从不使用强制。三向比较(由cmp()实现)的确在与其他二进制操作相同的条件下使用强制。

  • 在当前实现中,内置数字类型intlongfloatcomplex不使用强制。所有这些类型都实现coerce()方法,供内置coerce()函数使用。

在 2.7 版中进行了更改:复杂类型不再对混合类型的二进制算术运算进行coerce()方法的隐式调用。

3.4.10. 使用语句上下文 Management 器

2.5 版的新Function。

  • 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.4.11. 老式类的特殊方法查找

对于老式类,总是以与任何其他方法或属性完全相同的方式查找特殊方法。无论是在x.__getitem__(i)中显式查找方法还是在x[i]中隐式查找方法,都是这种情况。

此行为意味着,如果适当地设置了不同的特殊属性,则特殊方法对于单个旧类的不同实例可能表现出不同的行为:

>>> class C:
...     pass
...
>>> c1 = C()
>>> c2 = C()
>>> c1.__len__ = lambda: 5
>>> c2.__len__ = lambda: 9
>>> len(c1)
5
>>> len(c2)
9

3.4.12. new-style类的特殊方法查找

对于new-style类,只有在对对象的类型(而不是在对象的实例字典中)进行定义的情况下,才能保证对特殊方法的隐式调用可以正常工作。该行为是以下代码引发异常的原因(与旧类的等效示例不同):

>>> class C(object):
...     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)。

Footnotes

  • [1]

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

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