场景
在开发中,我们会定义很多函数,很多时候,函数的参数来自与其他函数处理的结果,而且函数间的参数很多,每次赋值都比较麻烦,为了方便理解,这里给出一个最小示例。
def funcA():
return {
"name": "二两",
"age": "30",
"hobby": ["code", "read", "girl"],
"job": "software engineer"
}
@choose_params
def funcB(name, age, job):
print(name, age, job)
def main():
res = funcA()
# 很麻烦
funcB(name=res['name'],
age=res['age'],
job=res['job'])
main()
解决
我想着,funcA 返回 dict 后,funcB 直接通过 **dict 的方式获得 funcB 需要的同名参数则可。
我们可以使用 inspect 内置库获得函数所有的参数名,示例如下:
In [1]: def funcB(name, age, job):
...: print(name, age, job)
...:
In [2]: import inspect
In [4]: inspect.getfullargspec(funcB).args
Out[4]: ['name', 'age', 'job']
inspect 内置库用处很多,主要可以实现下面的一些常见需求
1. 对类,模块的操作,成员,类,模块类型的判断
2. 获取源码
3. 获取类或函数的参数信息
4. 解析堆栈
基于「inspect.getfullargspec (funcB).args」,我们可以写一个装饰器,试一下 funcB (**res) 可以正常使用 funcB 的效果,装饰器代码如下:
import functools
import inspect
def choose_params(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 被装饰方法参数的名称
varnames = inspect.getfullargspec(func).args
_params = {k: kwargs.get(k) for k in varnames}
if 'self' in _params:
# 装饰类中方法时,去除self
del _params['self']
res = func(*args, **_params)
return res
return wrapper
使用上装饰器后,一开始示例的完整代码如下:
import functools
import inspect
def choose_params(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
varnames = inspect.getfullargspec(func).args
_params = {k: kwargs.get(k) for k in varnames}
if 'self' in _params:
del _params['self']
res = func(*args, **_params)
return res
return wrapper
def funcA():
return {
"name": "二两",
"age": "30",
"hobby": ["code", "read", "girl"],
"job": "software engineer"
}
@choose_params
def funcB(name, age, job):
print(name, age, job)
def main():
res = funcA()
funcB(**res)
main()