关于python装饰器实现的一点疑问

谢邀。
不是 wrapper 的参数从 func 里接收,而是 add 被 wrapper 替换了,wrapper 再去调用 func(即 add)。
装饰器引入的故事大概如下:
背景
在现实中,我们要举办一场晚会,我们往往需要在晚会之前搭建舞台,在晚会结束的时候把舞台拆掉,虽然我们大部分时候只关心晚会的安排,可是搭建和拆卸舞台的步骤往往是不能避免的。
我们可以抽取舞台搭建和拆卸的步骤,不需要在每次的晚会的策划中来描述,只需要在晚会的安排的前后都加上这些特定的步骤即可。
在编程中,有一种编程方式叫面向切面编程(AOP),一般实现是对具体的实现函数进行包装替换,在执行之前或之后加上一些必须的步骤,达到扩展原有函数的目的。
Python 装饰器定义
装饰器定义(1):
@dec2@dec1def func(arg1, arg2, ...): pass
相当于(2):
def func(arg1, arg2, ...): passfunc = dec2(dec1(func))
简单来说,装饰器只是个语法糖,其作用是将函数替换的操作放在了函数声明之前,使得更为紧凑可读。
其中引入装饰器这个语法有以下的原因:
在较长函数中,替换的操作容易被挤出屏幕而容易被忽略(2)中的方式看上去像是重复定义了多次函数 func为了解决这个问题,引入了装饰器语法,要求如下:
可以带构造参数可以在一个声明中使用多个装饰器装饰器对现有代码没有侵入性,以至于可以被忽略容易被扩展和分析优化为了实现这个要求,社区有过很激烈的讨论,其中也提出了很多语法版本,最后 Guido 毅然选择了从 JAVA 借鉴的@标记,确定了这一个简单清晰的语法。
总体来说,装饰器的引入是因为有大量(2)中的情况存在导致了一些可读性问题。
评论区同学问:
装饰器为什么要写的这么麻烦和难以理解啊?这样的写的好处是什么?这是一个简单的装饰器:def log(func): def wrapper(*args, **kw): print(\u0026#39;开场舞\u0026#39;) return func(*args, **kw) return wrapper但完全可以写成这样:def log(func): print(\u0026#39;开场舞\u0026#39;) return func调用时候:func = log(func())这样不也可以么? 这个问题类似于这个问题:Python中 pickle有什么意义,pickle了再恢复?
我们看待这种问题要站在现实角度去看,思考问题背景和明确要解决的问题。
很不幸,装饰器要解决的问题恰好是你说的那种更简单的描述方式。
首先我们把调用方和声明方拆开看,调用方是甲方,声明方是乙方。
那么需求就是甲方要办一场舞会,乙方来完成。
所以搭建舞台理应是乙方要做的事情,乙方也不能因为麻烦而让甲方亲历亲为指挥每个步骤,这样即便一个甲方可行,也不代表每个甲方都能这样正确操作。
但是我们假设我们遇到的都是十分友好的甲方,每个都能正确指挥乙方,事情是不是就解决了呢?
并没有。
如果舞会流程产生了变化,需要加入额外的一个步骤,比如向有关部门申请的硬性条件,那我们是不是要联系所有甲方来加入这个流程?
这个工作量和麻烦的程度可是远远大于乙方内部适应变化。
更要命的是,我们难以保证所有的甲方都能协调好,没有遗漏。
因此一种妥协的方式就是乙方把所有事情处理好,麻烦就麻烦一点,一旦乙方协调好了,收益的是每个甲方。
所以结论是:
当前装饰器实现方式不够优雅,甚至有不少问题,但这种已经是语法和需求互相妥协的结果了。

■网友
是func接收wrapper的参数。你在后面的代码使用add函数时,实际上调用的是wrapper函数,参数是传给wrapper函数的,在wrapper函数内部调用add函数时,就用这些参数来调用add函数了啊
■网友
def wrapper(*args, **kw): print(\u0026#39;call %s():\u0026#39; % func.__name__) return func(*args, **kw)这个是这样的,函数wrapper的参数args 和kw 也是局部变量,后面的func函数可以以这个局部变量为参数调用这个func函数。


推荐阅读