# 内置变量

  • 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 解释器自动赋值。
    • 当脚本被直接运行时,其值为执行该脚本时使用的文件路径(可能为绝对路径、相对路径)。
    • 当脚本被间接运行时,其值为该脚本的绝对路径。

# __name

__name__
  • 功能:记录当前脚本的名称,由 Python 解释器自动赋值。
    • 当脚本被直接运行时,其值为固定值 "__main__"
    • 当脚本被间接运行时,其值为该脚本的模块名,即将脚本的文件名去掉 .py 后缀。
  • 例:编写一个 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:
            main()
        except:
            raise
    

# __all

__all__
  • 功能:一个列表,决定了用 from xx import * 导入该脚本时,会导入哪些成员。
    • 如果用户没有定义该属性,则默认会导入该脚本内的所有公有成员(即不以下划线 _ 开头的标识符)。
  • 例:
    from sys import path
    
    __all__ = ['path', 'fun1']
    
    def fun1():
        pass