文章参考:https://blog.csdn.net/jiang_huixin/article/details/112468649
使用装饰器后, 原函数被内层函数赋值覆盖, 会导致函数名称等信息丢失了(装饰器仅仅是不改变函数原有功能)
使用 func_1 去包装 demo 函数, demo 函数本身的功能没变(仍打印 “demo”), 但是 __name__(函数名称), __doc__(函数文档), __annotations__(函数注释) 等属性变了, 而且 __wrapped__ 属性指向包装函数
functools.wrap
可用于装饰器的内层函数, 抵消装饰器的副作用
@info 装饰器等价于 multiply = info(multiply), 所以 func 指向原始 multiply 函数, @functools.wraps(func) 使用原始 multiply 函数包装 wrap 函数, 随后 wrap 函数覆盖原始 multiply 函数
注意 wrap 函数与原始 multiply 函数形参必须兼容