在 Python 中,函数是一等对象。编程语言理论家把 “一等对象” 定义为满足下述条件的程序实体:
- 在运行时创建
- 能赋值给变量或数据结构中的元素
- 能作为参数传递给函数
- 能作为函数的返回结果
函数内省
与用户定义的常规类一样,函数使用 __dict__
属性存储赋予它的用户属性。但是,函数也拥有一些专有而用户定义的一般对象没有的属性:
__annotations__
:dict
类型,参数和返回值的注解。__call__
:method-wrapper
类型,实现()
运算符,即可调用对象协议。__closure__
:tuple
类型,函数闭包,即自由变量的绑定。__code__
:code
类型,编译成字节码的函数元数据和函数定义体。__defaults__
:tuple
类型,形式参数的默认值。__get__
:method-wrapper
类型,实现只读描述符协议。__globals__
:dict
类型,函数所在模块中的全局变量。__kwdefaults__
:dict
类型,仅限关键字形式参数的默认值。__name__
:str
类型,函数名称。__qualname__
:str
类型,函数的限定名称,如Random.choice
。
在这里要说明一下,仅限关键字参数是 Python 3 中的新特性,仅限关键字参数只能通过关键字参数指定,它一定不会捕获未命名的定位参数:
1 | # cls 为仅限关键字参数 |
获取关于参数的信息
我们以在 clip.py
模块下定义的 clip
函数作为示例:
1 | def clip(text, max_len=80): |
通过 __code__
对象来获取函数信息未免有些不方便,我们一般会使用 inspect
模块来获取函数相关信息:
1 | In [29]: from inspect import signature |
inspect.signature
函数返回一个 inspect.Signature
对象,它有一个 parameters 属性,这是一个有序映射,把参数名 inspect.Parameter
对象对应起来。inspect.Parameter
对象的 kind
属性有以下五种值:
- POSITIONAL_OR_KEYWORD:可以通过定位参数和关键字参数传入的形参。
- VAR_POSITIONAL:定位参数元组。
- VAR_KEYWORD:关键字参数字典。
- KEYWORD_ONLY:仅限关键字参数(Python 3 新增)。
- POSITIONAL_ONLY:仅限定位参数;目前,Python 声明函数的句法不支持,但是有些使 用 C 语言实现且不接受关键字参数的函数(如
divmod
)支持。
inspect.Signature
对象有个 bind
方法,它可以把任意个参数绑定到签名中的形参上,所用的规则与实参到形参的匹配方式一样。框架可以使用这个方法在真正调用函数前验证参数:
1 | In [33]: import inspect |
支持函数式编程的包
operator 模块
比较哟用的两个函数是 itemgetter
及 attrgetter
,由于 itemgetter
使用的是 []
运算符来取值,所以其不仅仅支持序列,还支持映射和任何实现 __getitem__
方法的类:
1 | In [1]: from operator import itemgetter |
attrgetter
与 itemgetter
作用类似,它创建的函数根据名称提取对象的属性。如果把多个属性名传给 attrgetter,它也会返回提取的值构成的元组。此外,如果参数名中包含 .
(点号),attrgetter
会深入嵌套对象,获取指定的属性。
在 operator
模块余下的函数中,最后介绍一下 methodcaller
,其创建的函数会在对象上调用参数指定的方法:
1 | In [11]: from operator import methodcaller |
functools 模块
另外,我们也可以透过 functools
中的 partial
和 partialmethod
函数来将现有函数的某些参数固定来生成新的函数,减少重复并提升代码的可读性,这两个函数在此不多做赘述。