Python3中的函数对象

发布时间 2023-06-19 13:25:06作者: 韩志超

在Python中一切皆对象,函数也是一种对象,有相关的属性和方法。
对于任意对象,我们可以用dir()函数来获取其内置的属性及方法名,例如:

def add(a: int, b: int=1) -> int:
    """加法函数"""
    return a + b

print(dir(add))

运行结果如下:

['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

函数常见属性

函数常见属性如下:

属性 返回类型 说明
__name__ str 函数名
__qualname__ str 函数限定名,例如,函数在一个类中时,其限定名为 类名.函数名
__doc__ str or None 函数注释(docstring)
__anotations__ dict or None 函数函数参数及返回值类型注释
__module__ str 函数所属模块名
__class__ 类对象 函数所属类(对象)
__code__ code对象 函数代码(对象)
__defaults__ tuple or None 函数参数默认值
__kwdefaults__ tuple or None 函数函数参数及返回值类型注释
__closure__ tuple of cell or None 闭包函数中引用的自由变量,元祖类型,其中每一个变量是一个cell对象

函数属性使用示例

示例1-函数基本属性

def add(a: int, b: int=1) -> int:
    """加法函数"""
    return a + b

print('函数名:', add.__name__)
print('函数限定名:', add.__qualname__)
print('函数注释(docstring):', add.__doc__)
print('函数参数及返回值类型注释:', add.__annotations__)
print('函数所属类(对象):', add.__class__)
print('函数所属模块名:', add.__module__)
print('函数参数默认值:', add.__defaults__)

输出结果如下:

函数名: add
函数限定名: add
函数注释(docstring): 加法函数
函数参数及返回值类型注释: {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
函数所属模块名: __main__
函数所属类(对象): <class 'function'>
函数代码(对象): <code object add at 0x1043d0a80, file "/Users/superhin/Library/Application Support/JetBrains/PyCharm2023.1/scratches/scratch_11.py", line 19>
函数参数默认值: (1,)
函数限定关键值参数默认值: None

示例2-函数名及函数限定名

class Calc:
    def add(self, a, b):
        return a + b
print('函数名:', Calc.add.__name__)
print('函数限定名:', Calc.add.__qualname__)

输出结果如下:

函数名: add
函数限定名: Calc.add

示例3-关键字限定参数默认值

函数中可以使用独立的*参数,其后的参数在使用函数时仅可以按key=value形式传参

def add(*, a, b=1):
    return a + b

# add(1,2)  # ❌报错,不允许按位置参数形式使用
# add(a=1, b=2) # 可用
print('函数限定关键值参数默认值:', add.__kwdefaults__)

输出结果如下:

函数限定关键值参数默认值: {'b': 1}

示例4-闭包函数获取自由变量列表

def calc(method, a, b):
    def add():
        return a + b

    if method == 'add':
        return add
    # ...

add = calc('add', 1, 2)  # 得到闭包函数add
print('回调函数中自由变量列表', add.__closure__)
for cell in add.__closure__:
    print('自由变量值:', cell.cell_contents)

输出结果如下:

回调函数中自由变量列表 (<cell at 0x1113caaf0: int object at 0x10c8ef930>, <cell at 0x1113ca9d0: int object at 0x10c8ef950>)
自由变量值: 1
自由变量值: 2

注:由于闭包函数add中未使用外部函数的method变量,因此其不会出现在add的__closure__中。

函数代码对象常见属性

参考:PyCodeObject与Python程序执行

函数的__code__属性返回一个code(Python字节码)对象,该对象常见属性如下:

  • co_filename:代码所在文件路径

  • co_firstlineno: 函数代码第一行行号

  • co_cellvars: tuple cell变量名(参数名)列表

  • co_varnames: tuple 局部变量名列表

  • co_freevars:自由变量名列表

  • co_argcount: int 参数数量(不包含限定关键字参数)

  • co_nlocals:int 局部变量数量

  • co_kwonlyargcount:int 限定关键字参数数量

  • co_posonlyargcount:int 限定位置参数数量

  • co_names:所使用名称列表

  • co_consts:所使用常量列表,包含函数的docstring、代码对象,和内部函数等

  • co_code:bytes 编译后的二进制操作码(opcodes)

  • co_lnotab:地址及代码行号映射编码后的字符串

  • co_flags:标记列表

  • co_stacksize:使用的栈大小