# 内置变量
- Python 解释器会给一些对象,自动添加一些内置变量。
- 内置变量的命名特点:以两个下划线
__
开头,以两个下划线__
结尾。
- 内置变量的命名特点:以两个下划线
# 关于函数
每个函数中,存在以下内置变量:
# __name
__name__
- 功能:记录当前函数的名称,取值为 str 类型。
- 例:
>>> f = print # 即使将函数名赋值给一个变量, __name__ 依然记录的是原来的函数名 >>> f.__name__ 'print'
# __doc
__doc__
- 功能:记录当前函数的说明文档,取值为 str 类型。
- 例:
>>> print.__doc__ # 函数的说明文档,也就是执行 help(print) 看到的帮助文档 "print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n\nPrints the values ..."
# __defaults
__defaults__
- 功能:记录函数各个形参的默认值,取值为 tuple 类型。
- 例:
>>> def fun1(x=[], y=[]): ... print(fun1.__defaults__) ... print(x, y) ... y.append(0) # 形参 y 的默认值为 list 类型,可以被修改,修改结果会持久保留在 __defaults__ 中 ... >>> fun1() ([], []) [] [] >>> fun1() ([], [0]) [] [0]
# __annotations
__annotations__
- 功能:记录函数头中的注释,取值为 dict 类型。
- 例:
>>> def fun1(a, b: 'str或None', c: int = 0) -> int: # 定义函数时,可以用冒号 : 给形参添加注释 ... pass ... >>> fun1.__annotations__ {'b': 'str或None', 'c': <class 'int'>, 'return': <class 'int'>}
# __closure
__closure__
- 功能:对于非闭包函数,它没有用处,取值为 None 。对于闭包函数,它会记录函数引用的所有自由变量,取值为 tuple 类型。
- 例:
>>> def fun1(): ... x = 1 ... def fun2(): ... print(x) ... return fun2 ... >>> fun2 = fun1() >>> fun2.__closure__ (<cell at 0x000001EF96373970: int object at 0x000001EF962E6930>,) >>> fun2.__closure__[0].cell_contents 1
# 关于方法
每个方法中,存在以下内置变量:
# __name
__name__
- 功能:记录当前方法的名称。
- 例:
>>> str.encode.__name__ 'encode'
# __self
__self__
- 功能:它指向当前实例,相当于 self 指针。
- 例:
>>> class Test: ... def method1(self): ... pass ... @classmethod ... def method2(cls): ... pass ... @staticmethod ... def method3(): ... pass ... >>> t = Test() >>> t.method1.__self__ # 实例方法的 __self__ 变量,指向当前实例 <__main__.Test object at 0x000001EF96C73370> >>> t is _ True >>> t.method2.__self__ # 类方法的 __self__ 变量,指向当前类 <class '__main__.Test'> >>> Test is _ True >>> t.method3.__self__ # 静态方法实际上就是一个函数,没有 __self__ 变量 AttributeError: 'function' object has no attribute '__self__'
# __func
__func__
- 功能:它指向当前方法绑定的函数名。
- 在 Python 底层,类的每个方法,是通过函数实现的。
- 普通方法、类方法会绑定到一个函数,各个实例都是调用该函数。
- 静态方法实际上就是一个函数,没有
__func__
变量。
- 例:
>>> class Test: ... def method1(self, a): ... return a ... >>> t = Test() >>> t.method1.__func__ <function Test.method1 at 0x000001EF96C780D0> >>> t.method1.__func__() # __func__ 变量指向一个函数,可以调用它,但需要传入 self 参数 TypeError: method1() missing 2 required positional arguments: 'self' and 'a' >>> t.method1.__func__(t, 'hello') 'hello'
# 关于类
每个类中,存在以下内置变量:
# __name
__name__
- 功能:记录当前类的名称。
- 例:
>>> str.__name__ 'str'
# __bases
__bases__
- 功能:记录当前类的直接父类(不包括祖先类)。
- 例:
>>> class Test(int): ... pass ... >>> Test.__bases__ (<class 'int'>,)
# __mro
__mro__
- 功能:记录当前类的所有父类(包括祖先类)。
- 例:
>>> class Test(int): ... pass ... >>> Test.__mro__ (<class '__main__.Test'>, <class 'int'>, <class 'object'>)
# __slots
__slots__
- 功能:记录所有实例变量的名称。
- 主要用途是,减少每个实例的内存开销。
- 从类创建一个实例时,默认会为该实例添加一个内置变量
__dict__
,用于在一个字典结构中,存储所有实例变量的名称、取值。 - 如果该类中存在
__slots__
,则不会添加__dict__
,而是将所有实例变量,存储在一个紧凑的数组中,从而减少内存开销。
- 从类创建一个实例时,默认会为该实例添加一个内置变量
- 次要用途是,限制所有实例变量的名称,禁止添加额外的实例变量。
>>> class Test: ... __slots__ = ('a', 'b') # 在一个 tuple 中,包含所有实例变量的名称 ... def __init__(self): ... self.a = 0 ... >>> t = Test() >>> t.a # 实例变量 a 已初始化 0 >>> t.b # 实例变量 b 未初始化,但允许添加它 AttributeError: b >>> t.b = 0 >>> t.c = 0 # 实例变量 c 不允许添加,因为不包含在 __slots__ 中 AttributeError: 'Test' object has no attribute 'c'
- 如何继承父类的
__slots__
?- 定义一个类时,如果未声明
__slots__
,则不会继承父类的__slots__
。 - 定义一个类时,如果声明了
__slots__
,则会与父类的__slots__
合并。
- 定义一个类时,如果未声明
# 关于实例
每个实例对象中,存在以下内置变量:
# __class
__class__
- 功能:记录当前对象所属的类。
- 例:
>>> a = 1 >>> a.__class__ <class 'int'> >>> type(a) # 执行内置函数 type() 时,实际上就是读取 __class__ 变量 <class 'int'> >>> int.__class__ # 一个类,也有 __class__ 变量。可见在 Python 底层,类是从元类 type 创建的实例 <class 'type'> >>> print.__class__ # 一个函数,也有 __class__ 变量。可见在 Python 底层,函数是从某个类创建的实例 <class 'builtin_function_or_method'>
- 例:
# __dict
__dict__
- 功能:存储当前对象的所有实例变量的名称、取值。
- 例:
>>> class Test: ... a = 0 ... def __init__(self): ... self.b = 0 ... >>> t = Test() >>> t.__dict__ # 查看当前的所有实例变量 {'b': 0} >>> t.c = 0 # 添加实例变量 >>> t.__dict__ {'b': 0, 'c': 0}
__dict__
的取值为 dict 类型,支持索引、赋值:>>> t.__dict__['b'] 0 >>> t.__dict__['b'] = 0
# 关于脚本
每个 Python 脚本中,存在以下内置变量:
# __file
__file__
功能:记录当前脚本的文件路径,由 Python 解释器自动赋值。
- 当前脚本被直接运行时,其值为用户执行该脚本时,使用的文件路径(可能为绝对路径、相对路径)。
- 当前脚本被间接运行时,其值为该脚本的绝对路径。
例:获取当前脚本所属的磁盘目录
import os os.path.abspath(os.path.dirname(__file__))
# __name
__name__
功能:记录当前脚本的名称,由 Python 解释器自动赋值。
- 当前脚本被直接运行时,其值为固定值
"__main__"
。 - 当前脚本被间接运行时,其值为该脚本的模块名,即将脚本的文件名去掉 .py 后缀。
- 当前脚本被直接运行时,其值为固定值
在 Python 交互式终端中,不存在
__file__
变量,存在__name__
变量。>>> __file__ NameError: name '__file__' is not defined >>> __name__ '__main__'
例:编写一个 test.py 文件,内容如下
print(__file__) print(__name__)
执行该脚本,其输出为:
[root@CentOS ~]# python test.py test.py __main__ [root@CentOS ~]# python /root/test.py /root/test.py __main__
在 Python 交互式终端,导入该脚本,其输出为:
>>> import test /root/test.py test
例:如果当前脚本被直接运行,则会执行以下语句块。如果当前脚本被间接运行,则不会执行以下语句块
if __name__ == '__main__': try: do_sth() except: raise
# __package
__package__
- 功能:记录当前脚本所属的包名,由 Python 解释器自动赋值。
- 如果当前脚本不位于一个包中,则该变量取值为 None 。
- 如果在 Python 交互式终端中,则该变量取值为 None 。
# __all
__all__
- 功能:一个列表,决定了用
from xx import *
导入该脚本时,会导入哪些成员。- 如果用户没有定义该变量,则默认会导入该脚本内的所有公有成员(即不以下划线
_
开头的标识符)。
- 如果用户没有定义该变量,则默认会导入该脚本内的所有公有成员(即不以下划线
- 例:
import time __all__ = ['time', 'fun1'] def fun1(): pass