接上篇:[译]Python 语言参考-3.2. 标准类型层次(上)
可调用类型
此类型表示可被函数(参考
Calls
章节)调用:自定义函数(User-defined functions)
一个自定义函数对象被“函数定义说明”(参考函数定义章节)创建。它应该能够和与它的参数个数相等的参数列表一起,作为函数的正式参数。
特殊属性:
属性 含义 __doc__
函数的文档字符串,如果不可用则为 None
;不会被子类继承。可写 __name__
函数名。 可写 __qualname__
函数的合法名
3.3版本新添加。可写 __module__
函数定义所在的模块名,如果不可用则为 None
。可写 __defaults__
一个包含默认参数值的元组,该元组由拥有默认值的参数的默认值组成。如果没有参数拥有默认值,则返回 None
。可写 __code__
代表编译后函数体的代码对象。 可写 __globals__
一个包含函数全局变量——函数定义所在模块的全局命名空间——的字典的引用。 只读 __dict__
任意函数属性的命名空间。 可写 __closure__
None
或者包含为函数绑定自由变量格子的元组。只读 __annotations__
包含参数注解的字典。字典的键是参数名,如果提供返回注解,则为 'return'
。可写 __kwdefaults__
包含默认的只限关键字参数的字典。 可写 多数被标记为“可写”的属性在赋值时会检查类型。
函数对象也支持获取(getting)和设置(setting)任意可被使用的属性,例如:将元数据绑定到函数上。常规属性使用点号获取。注意,当前的实现仅支持自定义函数的属性。将来的版本可能会支持内建函数的属性。
其他关于函数定义的信息可从它的代码对象中解锁;参考下面的内部类型描述。
实例方法
一个实例方法对象将一个类,一个类实例和任意可调用的对象(通常是自定义函数)组合起来。
特殊的只读属性:__self__
是一个类实例对象,__func__
是一个函数对象;__doc__
是方法的文档说明(和__func__.__doc__
一样);__name__
是方法名(和__func__.__name__
一样);__module__
是方法定义所在模块的名称,如果不可用则为None
。方法也支持访问任意底层函数的属性,但不能设置属性值。
当获取一个类的属性时(也许通过该类的实例获取),如果属性是一个自定义函数对象或一个类方法对象可能会创建自定义方法对象。
当一个实例方法对象通过检索一个类实例的自定义函数对象创建时,它的
__self__
属性是这个实例,方法对象称为被绑定的对象。新方法的__func__
属性是源函数对象。当一个自定义函数对象通过检索一个类或实例的其他方法对象创建时,它的行为和一个函数对象一致。除非新实例的
__func__
属性不是源生方法对象(除了它的__func__
属性外)。当通过检索一个类或实例的类方法对象创建一个实例方法对象时,它的
__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
语句或者执行到了最后,会抛出一个StipIteration
异常,这时迭代器已经到达了待返回值集合的末尾。协同函数(Coroutine functions)
使用
async def
定义的函数或方法称为协同函数。调用此类函数会返回一个协同程序(coroutine
)对象。它可能包含await
表达式,同async with
和async for
语句相同。参考协同程序对象
章节。内建函数
内建函数对象是对 C 函数的包装。例如内建函数
len()
和math.sin()
(math
是标准的内建模块)。参数类型和个数由 C 函数决定。一些特殊的只读属性:__doc__
是函数的文档字符串,如果不可用则为None
;__name__
是函数名;__self__
被设置为None
(but see the next item);__module__
是函数定义所在模块的名字,如果不可用则为None
。内建方法
和内建函数不同,内建方法包含一个作为附加参数传递给 C 函数的对象。例如内建方法
alist.append()
,假设alist是一个列表对象。这种情况下,特殊的只读属性__self__
被设置为alist指向的对象。类
类是可调用的。类一般作为它们自己创建对象的工厂存在,但类的变种可能会重写
__new__()
函数。调用时会将参数传递给__new__()
,而通常情况下,都是传递给__init__()
来创建一个新实例。类实例
任意类的实例只要在他们的类中定义一个
__call()__
函数,就都可被调用。
模块(Modules)
模块是 Python 代码中一个基本的组织单位,被
import system
创建,可通过import
语句(查看import),调用类似importlib.import_module()
函数,或者内建__import__()
函数调用。模块对象有一个用字典对象(被定义在该模块中的函数属性__globals__
引用的字典)表示的命名空间。为了能在字典中查找,属性引用会被转化,例如:m.x
与m.__dict__["x"]
相同。模块对象不包含实例化模块的代码对象(因为一旦模块初始化完毕,就不需要该对象了)。给属性赋值会更新模块的命名空间字典,例如:
m.x = 1
与m.__dict__["x"] = 1
相同。特殊的只读属性:
__dict__
是模块的命名空间,以字典对象形式存在。CPython 实现细节:根据 CPython 清空模块字典的方式,即使仍有可用引用指向模块字典,它也会在模块超出范围后被清空。为了避免这种情况发生,在直接使用模块的字典时,你可以拷贝该字典或确保模块不超出范围。
预定义可写属性:__name__
是模块名;__doc__
是模块的文档字符串,如果不可用则为None
;如果从一个文件中加载模块,则__file__
是加载该模块的文件的路径名。__file__
属性在某些模块中不存在,比如静态链接到解释器的 C 模块;对于从共享库中动态加载的扩展模块而言,__file__
是共享库文件的路径名。
自定义类
自定义类型通常通过类定义说明(参考类定义说明章节)创建。自定义类都有一个用字典对象表示的命名空间。为了能在字典中查找,属性引用会被转化。例如:
C.x
会转化为C.__dict__["x"]
(尽管有一些允许通过其他方式定位属性的钩子)。当属性不在自定义类时,会继续在基类中寻找该属性。Python 使用 C3 方法解析顺序(C3 method resolution order)在基类中查找,该方法即使在“宝石”继承结构(多个继承路径指向同一个祖先)中也表现得体。 C3 MRO 的详细信息可在伴随 2.3 版本发行的文档中查看:https://www.python.org/download/releases/2.3/mro/。当一个类(比如类
C
)的属性引用指向一个类方法对象时,它会被转化为__self__
属性为 C 的实例方法对象。当指向一个静态方法对象是,它会被转化为静态方法对象的包装对象。查看实现描述符章节中另一种从类中检索的属性的方法,此方法检索出的属性可能与在__dict__
中实际包含的不同。类的属性赋值会更新类的字典,基类字典不会更新。
类对象可以被调用(参考上面)来指向一个类实例(参考下面)。
特殊属性:
__name__
是类名;__module__
是类定义所在模块的模块名;__dict__
是包含类命名空间的字典;__bases__
是一个包含基类的元组(可能为空或单元组),在基类列表中以它们出现的顺序排列;__doc__
是类的文档字符串,如果不可用则为None
。
类实例
类实例通过调用类对象创建(参考上面)。类实例有一个以字典形式实现的命名空间,该字典是检索属性引用时的首选位置。当属性不在字典中,而实例对应的类有此属性时,会继续搜索类中的属性。如果一个类的属性是自定义函数对象,它会被转化为一个
__self__
属性是该实例的实例方法对象。静态方法和类方法对象也会被转化;参考上面的“类”。查看实现描述符章节中另一种从类实例中检索类属性的方法,此方法检索出的属性可能与在类的__dict__
中实际包含的不同。如果类属性没有找到,并且对象对应的类有__getattr__()
方法,该方法会被调用以用来查找。赋值或删除属性会更新实例字典,类字典不会更新。如果类有
__setattr__()
或__delattr__()
方法,该方法会被调用,而不是直接更新实例字典。如果类实例有一些特定名称的方法,它们可以伪装成数字,序列,或者映射集合。参考特定方法名章节。
特殊属性:__dict__
是一个字典属性;__class__
是一个实例对应的类。
I/O 对象(也被称为文件对象)
文件对象代表了一个打开的文件。有很多创建对象的捷径:内建函数
open()
,os.popen()
,os.fopen()
和 socket 对象的makefile()
方法(也可能通过其他扩展模块中的方法创建)。
sys.stdin
,sys.stdout
,sys.stderr
对象被初始化为文件按对象,分别对应解释器的标准输入,输出和错误流;它们都是以文本模式打开,遵守符合io.TextIOBase
抽象类的接口定义。
内部类型
少数被解释器内部使用的类型暴露给了用户。它们的定义可能会在在未来版本的解释器中改变,但是为了保持完整性,此处还是提及了他们。
代码对象(Code objects)
代码对象代表字节编译(byte-compiled)的可执行 Python 代码,或者是字节码。代码对象和函数对象的区别在于:函数对象包含一个明确的对函数全局的引用(函数定义所在模块),而代码对象不包含上下文;而且默认参数值会存在函数对象中,而不在代码对象中,因为他们代表运行时被计算出的值。不像函数对象,代码对象是不可变的而且不包含对(直接或继承的)可变对象的引用。
特殊的制度属性:
co_name
给出函数名;co_argcount
是位置参数(positional arguments)的个数(包含带默认值的参数);co_nlocals
是供函数使用的局部变量(包含参数)的个数;co_varnames
是一个包含局部变量名的元组(从参数名开始);co_cellvars
是一个包含被嵌套函数引用的局部变量名的元组;co_freevars
是一个包含自由变量名的元组;co_code
是一个代表字节码指令序列的字符串;co_consts
是一个包含字节码使用的字面值的元组;co_names
是一个包含被字节码使用的名称的元组;co_filename
是被编译代码所在的文件名;co_firstlineno
是函数的第一行的行号;co_lnotab
是一个编码从字节码坐标到行号的映射集合的字符串(查看解释器源码获取详细信息);co_stacksize
是请求的栈大小(包括局部变量);co_flags
是一个编码了一些解释器标识的整数。以下是为
co_flags
定义的标志位:如果函数使用了*arguments
语法来接受任意个位置参数,则放置标志位0x04
;如果函数使用了**keywords
语法来接受任意键值对参数,则放置标识位0x08
;如果函数是一个生成器,则放置标志位0x20
。将来特性声明(
from __future__ import division
)也用co_flags
中的标志位来标识代码对象使用一个指定特性编译的功能是否开启:如果函数使用将来版本编译功能开启,则放置标志位0x2000
;在早期的 Python 版本中使用0x10
和0x1000
。
co_flags
的其他标志位仅供内部使用。如果一个代码对象代表一个函数,那么
co_consts
的第一个元素是函数的文档字符串,如果不可达则为None
。帧对象(Frame objects)
帧对象代表执行帧。他们可能会出现在跟踪对象中(参考下面)。
特殊的只读属性:
f_back
指向之前的栈帧(用于调用者),如果当前已经在栈帧底部,则为None
;f_code
是帧中将要被执行的代码对象;f_locals
是用来查找局部变量的字典;f_globals
是用来查找全局变量的字典;f_buitins
用于内建(固有的)名字;f_lasti
给予精确地说明(是进入到代码对象字节码字符串的索引)。特殊的可写属性:
f_trace
如果不是None
,则为在每行源码开头处被调用的函数(用来调试);f_lineno
是帧当前的行号——在跟踪函数内部写入此属性,可以跳转到指定行(只针对最底层的帧使用)。通过向 f_lineno 写入,调试者可以实现一个跳转命令(也称为设置下一条语句)。帧对象支持一个方法:
frame.clear()
此方法清空帧持有的所有局部变量引用。同时,如果帧属于一个生成器,则生成器是最终化(finalized)的。此方法有助于打破对帧对象的循环引用(例如:当捕获到一个异常并存储它的跟踪信息,以备后来使用)。如果帧正在执行,则抛出
RuntimeError
异常。3.4版本新添加。
跟踪对象
跟踪对象代表一个异常的堆栈踪迹(stack trace)。当发生异常时跟踪对象被创建。当异常处理器展开执行栈进行搜索时,在每个展开层次中的跟踪对象都会插在当前跟踪对象的前面。当异常处理器介入后,堆栈踪迹对程序可访问。(参照try 语句章节。)它作为被
sys.exc_info()
返回的tuple中的第三个元素被访问。当程序没有合适的处理器时,堆栈踪迹以良好的格式被写入标准错误流中;如果解释器是交互式的,用户也可以通过sys.last_traceback
获取到它。特殊的只读属性:
tb_next
表示堆栈踪迹的下一个层次(指向程序发生异常处的帧),如果没有下一层次则为None
;tb_frame
指向当前层次的执行帧;tb_lineno
给出发生异常处的行号;tb_lasti
指的是精确的命令。在跟踪对象中行号和最后一次指令可能与帧对象发生异常的行号不一致,如果该异常发生在try
语句中,并且没有匹配的except
语句块或finally
语句块。切片对象
切片对象代表
__getitem__()
方法中的切片。它们也可以通过内建函数slice()
创建。特殊的只读属性:
start
是前边界;stop
是后边界;step
是步值;如果不提供值,则为None
。这些属性可以是任意类型。切片对象支持一个方法:
slice.indices(self, length)
此方法有一个整型的参数 length 并估算有关切片的信息,切片对象会描述是否应用连续的 length 元素。该方法返回一个包含三个整型的元组;这三个整型分别代表
start
,stop
和step
或切片的步长。未提供或超出边界的索引会按照符合正常切片的方法处理。静态方法对象
静态方法对象提供了阻止上述将函数对象转换为方法对象的方法。静态方法对象是一个对其他对象的包装,通常是一个自定义方法对象。当一个静态方法对象被类或类实例检索时,该对象实际上会返回一个包装对象,这个包装对象不会再做任何转换。静态方法对象本身是不可调用的,但它们的包装类是调用的。静态方法对象通过内建构造器
staticmethod()
方法创建。类方法对象
与静态方法对象类似,类方法对象是一个其他对象的包装,改变从类或类实例中检索对象的方式。类对象的行为决定于“自定义方法”中描述的检索方式。类方法对象通过内建构造器
classmethod()
创建。
译者结语
翻译真不是个好干的活,真心累啊!但官方文档真是宝啊,学到了很多东西,还需要慢慢消化理解。翻译完后,有时间要做个总结文档。
限于译者英文水平,如有翻译不当之处还请各位予以批评指正。也希望感兴趣的同学加入,共同学习,共同进步。
PS:部分名词中英对照:
英文 | 中文 |
---|---|
function | 函数 |
method | 方法 |
object | 对象 |
instance | 实例 |
User-defind | 自定义 |