Python3中的函数对象
在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) |
__annotations__ |
dict or None | 函数函数参数及返回值类型注释 |
__module__ |
str | 函数所属模块名 |
__class__ |
类对象 | 函数所属类(对象) |
__code__ |
code对象 | 函数代码(对象) |
__defaults__ |
tuple or None | 函数参数默认值 |
__kwdefaults__ |
tuple or None | 函数限定关键字参数默认值 |
__closure__ |
tuple of cell or None | 闭包函数中引用的cell变量 |
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__
中。
函数代码对象常见属性
函数的__code__
属性返回一个code(Python字节码)对象,该对象常见属性如下:
属性 | 返回类型 | 说明 |
---|---|---|
co_filename | str | 代码所在文件路径 |
co_firstlineno | int | 代码第一行行号 |
co_argcount | int | 常规参数数量 |
co_posonlyargcount | int | 限定位置参数数量 |
co_kwonlyargcount | int | 限定关键字参数数量 |
co_nlocals | int | 局部变量数量 |
co_varnames | tuple | 局部变量名列表 |
co_freevars | tuple | 自由变量名列表 |
co_cellvars | tuple | cell变量(多作用域变量)名列表 |
co_names | tuple | 引用其他函数名列表 |
co_consts | tuple | 所使用常量列表,包含函数的docstring、内部函数等 |
co_code | bytes | 编译后的二进制操作码(opcodes) |
co_lnotab | bytes | 地址及代码行号映射编码后的二进制 |
co_flags | int | 操作标记值 |
co_stacksize | int | 使用的栈大小 |
示例1-基本属性
def add(a, b):
"""加法函数"""
s = a + b
return s
code = add.__code__
print('函数代码所在文件路径:', code.co_filename)
print('函数代码第一行行号:', code.co_firstlineno)
print('参数数量:', code.co_argcount)
print('关键字限定参数数量:', code.co_kwonlyargcount)
print('位置限定参数数量:',code.co_posonlyargcount)
print('局部变量数量:', code.co_nlocals)
print('局部变量名列表:', code.co_varnames)
print('cell变量名列表:', code.co_cellvars)
print('自由变量名列表:',code.co_freevars)
print('所使用常量列表:', code.co_consts)
print('引用名称列表:', code.co_names)
print('编译后的二进制操作码:', code.co_code)
print('地址及代码行号映射编码后的二进制:', code.co_lnotab)
print('操作标记值:', code.co_flags)
print('使用栈大小:', code.co_stacksize)
输出结果如下:
函数代码所在文件路径: /Users/superhin/Library/Application Support/JetBrains/PyCharm2023.1/scratches/scratch_11.py
函数代码第一行行号: 98
参数数量: 2
关键字限定参数数量: 0
位置限定参数数量: 0
局部变量数量: 3
局部变量名列表: ('a', 'b', 's')
cell变量名列表: ()
自由变量名列表: ()
所使用常量列表: ('加法函数',)
引用名称列表: ()
编译后的二进制操作码: b'|\x00|\x01\x17\x00}\x02|\x02S\x00'
地址及代码行号映射编码后的二进制: b'\x00\x02\x08\x01'
操作标记值: 67
使用栈大小: 2
示例2-位置限定参数及关键字限定参数
def sub(a, b, /): # 限定位置参数
return a -b
def mul(*, a, b): # 限定关键字参数
return a * b
print('sub函数-参数数量:', sub.__code__.co_argcount)
print('sub函数-位置限定参数数量:', sub.__code__.co_posonlyargcount)
print('mul函数-参数数量:',mul.__code__.co_argcount)
print('mul函数-关键字限定参数数量:',mul.__code__.co_kwonlyargcount)
输出结果如下:
sub函数-参数数量: 2
sub函数-位置限定参数数量: 2
mul函数-参数数量: 0
mul函数-关键字限定参数数量: 2
示例3-引用函数名称列表
def add(a, b):
return a + b
def mul(a, b):
return a * b
def calc(x, y, z):
"""计算(x+y) * z"""
return mul(add(x, y), z) # 引用名称
print('calc函数-引用函数名列表:', calc.__code__.co_names)
输出结果如下:
calc函数-引用函数名列表: ('mul', 'add')
示例4-闭包及外部函数-cell变量及自由变量列表
def calc(method, a, b):
"""延迟计算"""
def add():
"""计算加法"""
return a + b
if method == 'add':
return add
# ...
add = calc('add', 1, 2) # 闭包函数
print('calc函数-cell变量名列表:', calc.__code__.co_cellvars)
print('calc函数-局部变量名列表:', calc.__code__.co_varnames)
print('calc函数-所使用常量列表:', calc.__code__.co_consts)
print('add函数-自由变量名列表:', add.__code__.co_freevars)
print('add函数-局部变量名列表:', add.__code__.co_varnames)
print('add函数-所使用常量列表:', add.__code__.co_consts)
输出结果如下:
calc函数-cell变量名列表: ('a', 'b')
calc函数-局部变量名列表: ('method', 'a', 'b', 'add')
calc函数-所使用常量列表: ('延迟计算', <code object add at 0x11030edf0, file "/Users/superhin/Library/Application Support/JetBrains/PyCharm2023.1/scratches/scratch_11.py", line 124>, 'calc.<locals>.add', 'add', None)
add函数-自由变量名列表: ('a', 'b')
add函数-局部变量名列表: ()
add函数-所使用常量列表: ('计算加法',)