引自:https://www.cnblogs.com/myd7349/p/how_to_use_wraps_of_functools.html
一、wraps装饰器使用
1、通过trace装饰器,打印函数调用内容(未使用wraps)
# coding: utf-8
# Filename: decorator_wraps_test.py
import sys
debug_log = sys.stderr
def trace(func):
if debug_log:
def callf(*args, **kwargs):
"""A wrapper function."""
debug_log.write('Calling function: {}\n'.format(func.__name__))
res = func(*args, **kwargs)
debug_log.write('Return value: {}\n'.format(res))
return res
return callf
else:
return func
@trace
def square(x):
"""Calculate the square of the given number."""
return x * x
if __name__ == '__main__':
print(square(3))
输出:
Calling function: square
Return value: 9
9
2、查看实际调用函数的内容
if __name__ == '__main__':
help(square)
print(square.__name__)
print('debug_log' in square.__globals__)
print('sys' in square.__globals__)
输出
callf(*args, **kwargs)
A wrapper function.
callf
True
True
与预期不一致,期待返回的是square函数的信息
实际返回的是装饰器trace返回的callf函数信息
如何解决这个问题呢,那么就需要使用functools的wraps
3、通过wraps实现,展示真实的函数调用
# coding: utf-8
# Filename: decorator_wraps_test.py
import functools
import sys
debug_log = sys.stderr
def trace(func):
if debug_log:
@functools.wraps(func)
def callf(*args, **kwargs):
"""A wrapper function."""
debug_log.write('Calling function: {}\n'.format(func.__name__))
res = func(*args, **kwargs)
debug_log.write('Return value: {}\n'.format(res))
return res
return callf
else:
return func
@trace
def square(x):
"""Calculate the square of the given number."""
return x * x
if __name__ == '__main__':
print(square(3))
print(square.__doc__)
print(square.__name__)
print('debug_log' in square.__globals__)
print('sys' in square.__globals__)
输出
Calling function: square
Return value: 9
9
Calculate the square of the given number.
square
True
True
通过functools的wraps实现了在获取“square.name”信息时,输出的是square
二、引申:wraps装饰器分析
对代码要求较高,比较感兴趣的话,可以了解下
1、带参数的装饰器
def trace(log_level):
def impl_f(func):
print(log_level, 'Implementing function: "{}"'.format(func.__name__))
return func
return impl_f
@trace('[INFO]')
def print_msg(msg):
print(msg)
@trace('[DEBUG]')
def assert_(expr):
assert expr
print_msg('Hello, world!')
输出
[INFO] Implementing function: "print_msg"
[DEBUG] Implementing function: "assert_"
Hello, world!
装饰器理解
@trace('[INFO]')
def print_msg(msg): print(msg)
等价于
temp = trace('[INFO]')
def _print_msg(msg): print(msg)
print_msg = temp(_print_msg)
2、partial函数
# coding: utf-8
from functools import partial
def foo(x, y, z):
print(locals())
foo(1, 2, 3)
foo_without_z = partial(foo, z = 100)
foo_without_z
foo_without_z is foo
foo_without_z(10, 20)
输出:
{'z': 3, 'y': 2, 'x': 1}
{'z': 100, 'y': 20, 'x': 10}
说明:
我们通过partial为foo提供参数z的值,得到了一个新的“函数对象”
foo_without_z和一般的函数对象有些差别。比如,foo_without_z没有name属性
文档字符串doc也和partial的文档字符串很相像
foo_without_z(10, 20)
等价于
foo(10, 20, z = 100)
网友评论