在 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 函数来将现有函数的某些参数固定来生成新的函数,减少重复并提升代码的可读性,这两个函数在此不多做赘述。