浅谈python装饰器的实现原理

一、装饰器
在初学装饰器的时候,会觉得抽象生涩,其实装饰器就是对某个对象进行功能上的增强
下面详细讲一下 “增强” 的实现原理

二、增强的实现原理
其实原理就一句话:更改旧对象的指向,指向 构造的新的函数wrapper

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
@log
def now():
    print('2015-3-25')
>>> now()
call now():
2015-3-25

上面是拿廖雪峰-python-装饰器中的例子,在此做一个详细说明:
a. python解释器在执行now()之前,首先加载环境,加载内存中对应的程序

b. 找到后,自上而下执行,于是先执行 @log
即执行: now = log(now)

我们来详细看一下log(now)发生了什么,重点关注指向对象的变化
1、首先解释器根据变量名log,找到内存中对应的程序
2、now函数传入log函数,重点来了,参数func和now 此时指向同一个对象,即内存中存储的
```
def now():
    print('2015-3-25')
```
3、此时解释器继续向下读取程序,直到遇到return返回。这里要注意,
此时调用的是log函数,log内部的wrapper函数(闭包)此时并没有被调用,
所以此时执行log函数的return语句`return wrapper`
log函数将`wrapper`返回

c. log(now)返回wrapper,然后赋值给now,重点来了,now变量指向的对象从

def now():
    print('2015-3-25')

变为

def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)

d. abc结束后,解释器执行完@log,接下来读取到now()语句,开始执行:

1. 此时now已经和wrapper指向同一个对象,这里多说一句,其实此时如果运行
    ```
    >>> now.__name__
    'wrapper'
    ```
如果想要避免这种情况,可以使用@functools.wraps(func)
2. 我们继续执行,遇到`print('call %s():' % func.__name__)`,执行print内容
3. 遇到`return func(*args, **kw)`,还记得吗,上面我们提到func指向的对象是谁?
4. 调用func
5. 解释器找到func指向的程序,
    ```
    def now():
        print('2015-3-25')
    ```

6. 执行 `print('2015-3-25')`

e. 至此,now()执行结束,根据abcd的说明,大家应该可以理解返回的结果了

>>> now()
call now():
2015-3-25

三、说明
为了解释的通俗易懂,请大家忽略上面一些话术用语的不准确。
这章内容没有涉及到装饰器的“外函数只执行一次”这一知识点,这个知识点正好和
装饰器实现单例模式 相关,所以打算放到那里讲,有兴趣的朋友可以去看。

四、考察
留一个小问题,now()的返回结果中,
为什么是 call now() 而不是 call wrapper() ?

hint:答案就在上面的讲解中。

1 声望
0 粉丝
0 条评论
推荐阅读
捕获异常Exceptions
如果divide函数这样写,会有四个弊端:1)繁琐针对三种返回结果,现在call_divide函数如果调用它,就必须对三种调用结果进行判断,然后处理逻辑。那如果还有call_call_divide函数调用call_divide呢?这意味着后面...

nanakio阅读 689

数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 5.2k

滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?

良许3阅读 1.4k

搭个ChatGPT算法模型,从哪开始?
最近 ChatGPT 很火,火到了各行各业。记得去年更多的还是码农最新体验后拿它搜代码,现在各行各业都进来体验,问它咋理财、怎么写报告和给小孩起名。😂 也因此让小傅哥在头条的一篇关于 ChatGPT 的文章都有了26万...

小傅哥6阅读 1.1k

封面图
程序员适合创业吗?
大家好,我是良许。从去年 12 月开始,我已经在视频号、抖音等主流视频平台上连续更新视频到现在,并得到了不错的评价。每个视频都花了很多时间精力用心制作,欢迎大家关注哦~考虑到有些小伙伴没有看过我的视频,...

良许3阅读 1.2k

Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4.5k评论 1

Python实现Windows弹出微信消息通知(可显示发送人和消息内容)
Mac微信是有一个消息通知的,这一点就挺好的,有时候根本不用点开开看就能看到消息内容。而Windows电脑版是没有这个消息通知的,只有右下角图标闪烁。

TANKING3阅读 3.7k评论 1

封面图
1 声望
0 粉丝
宣传栏