在 Python 中,函数是一等对象。那什么是“一等对象”呢?“一等对象”的定义如下:
- 在运行时创建
- 能赋值给变量或数据结构中的元素
- 能作为参数传给函数
- 能作为函数的返回结果
高阶函数
能接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higher-order function).
匿名函数
lambda 关键字在 Python 表达式内创建匿名函数。
一个例子
>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
>>> sorted(fruits, key=lambda word: word[::-1])
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
用户定义的可调用类型
只要实现对象的 __call__
方法,该对象就可以表现得像函数。
一个例子
class MyDemo:
def __call__(self):
return "hello world"
a = MyDemo()
print(a())
获取关于参数的信息
使用 imspect
模块来提取函数签名
def clip(text, max_len=80):
"""在max_len前面或后面的第一个空格处截断文本 """
end = None
if len(text) > max_len:
space_before = text.rfind(' ', 0, max_len)
if space_before >= 0:
end = space_before
else:
space_after = text.rfind(' ', max_len)
if space_after >= 0:
end = space_after
if end is None: # 没找到空格
end = len(text)
return text[:end].rstrip()
from inspect import signature
sig = signature(clip)
print(sig)
print(str(sig))
for name, param in sig.parameters.items():
print(param.kind, ':', name, '=', param.default)
"""
output:
(text, max_len=80)
(text, max_len=80)
POSITIONAL_OR_KEYWORD : text = <class 'inspect._empty'>
POSITIONAL_OR_KEYWORD : max_len = 80
"""
-
inspect.signature
函数返回一个inspect.Signature
对象,它有一个parameters
属性,这是一个有序映射,把参数名和inspect.Parameter
对象对应起来。各个Parameter
属性也有自己的属性,例如name
,default
和kind
。特殊的inspect._empty
值表示没有默认值,考虑到None
是有效的默认值,这么做是合理的。 -
kind
属性的值是_ParameterKind
类中的5个值之一,例举如下。POSITIONAL_OR_KEYWORD
- 可以通过定位参数和关键字参数传入的形参(多数Python函数的参数属于此类)
VAR_POSITIONAL
- 定位参数元组。
VAR_KEYWORD
- 关键字参数字典。
KEYWORD_ONLY
- 仅限关键字参数(Python3 新增)。
POSITIONAL_ONLY
- 仅限定位参数;目前,Python声明函数的句法不支持,但是有些使用C语言实现且不接受关键字参数的函数(如divmod)支持。
-
inspect.Signature
对象有个bind
方法,它可以把任意个参数绑定到签名中的形参上,所用的规则与实参到形参的匹配方式一样。框架可以使用这个方法在真正调用函数前验证参数。
def clip(text, max_len=80):
"""在max_len前面或后面的第一个空格处截断文本 """
end = None
if len(text) > max_len:
space_before = text.rfind(' ', 0, max_len)
if space_before >= 0:
end = space_before
else:
space_after = text.rfind(' ', max_len)
if space_after >= 0:
end = space_after
if end is None: # 没找到空格
end = len(text)
return text[:end].rstrip()
from inspect import signature
sig = signature(clip)
my_params = {'text': "abcd df", 'max_len': 3}
bound_args = sig.bind(**my_params)
print(bound_args)
for name, value in bound_args.arguments.items():
print(name, "=", value)
del my_params['text']
bound_args = sig.bind(**my_params)
"""
output:
<BoundArguments (text='abcd df', max_len=3)>
text = abcd df
max_len = 3
Traceback (most recent call last):
File "E:/code/python/py_study/test.py", line 28, in <module>
bound_args = sig.bind(**my_params)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\inspect.py", line 3015, in bind
return args[0]._bind(args[1:], kwargs)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\inspect.py", line 2930, in _bind
raise TypeError(msg) from None
TypeError: missing a required argument: 'text'
<BoundArguments (text='abcd df', max_len=3)>
text = abcd df
max_len = 3
"""
支持函数式编程的包
使用 functools.partial
冻结参数
functools.partial
这个高阶函数用于部分应用一个函数。部分应用是指,基于一个函数创建一个新的可调用对象,把原函数的某些参数固定。使用这个函数可以把接受一个或多个参数的函数改编成需要回调的API,这样参数更少。
一个例子
>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul, 3)
>>> triple(7)
21
>>> list(map(triple, range(1, 10)))
[3, 6, 9, 12, 15, 18, 21, 24, 27]
又写完一章啦,真希望快点结束这个专题。下一章我们将介绍如何使用一等函数实现设计模式