IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python装饰器与闭包 -> 正文阅读

[Python知识库]Python装饰器与闭包

说到python中的装饰器,很容易联想到设计模式中有个模式叫做装饰器模式,设计模式中的那个装饰器模式的本质其实就是装饰器类和被装饰类实现共同的接口,装饰器类中持有被装饰类的对象并且覆写被装饰类中的方法,覆写的方法中一边通过被装饰类的对象调用该对象自己的方法,一边自定义自己的装饰。python中的装饰器和上面的思想也是类似的。

1. python装饰器的一个简单实例实现

def logging(fn):
    def inner():
        print("被装饰函数执行之前log一下~")
        fn()
        print("被装饰函数执行之后log一下~")
    return inner


@logging
def fun():
    print("执行被装饰函数...")


if __name__ == '__main__':
    fun()

在这里插入图片描述

其中 @logging属于一种语法糖,作用上等价于fun = logging(fun)@logging根据装饰函数的函数名不同可以为 @xxx

2. python中装饰器的实现原理

把上面代码还原成不使用语法糖的格式也许更容易理解:

# 装饰函数
def logging(fn):
    def inner():
        print("装饰函数执行之前log一下~")
        fn()
        print("被装饰函数执行之后再log一下~")
    return inner

# 被装饰函数
def fun():
    print("执行被装饰函数...")


if __name__ == '__main__':
    fun = logging(fun)
    fun()

上面说过,@logging只是一种语法糖,目的是避免开发者自己手动的fun = logging(fun),繁琐而且容易出错,所以上面两段代码本质上是一样的,毫无区别。

从最后两行代码可以看出:此fun(main中的fun)非彼fun(main外的fun),二者只是同名,或者说,main外的fun已经被main中的fun覆盖了。此时的对应关系是:
1.main中的 fun <=> inner
2.main外的 fun <=> fn

最后的 fun() 其实调用的是 inner()。这,就是python中装饰器的实现原理。

3. 装饰带有不定长参数和返回值的函数实例

def logging(fn):
    def inner(*args, **kwargs):
        print("检查参数类型是否有误~")
        return fn(*args, **kwargs)	# 注意此处+return 没有的话会导致res为None
    return inner


@logging
def fun(*args, **kwargs):
    result = 0
    for i in args:
        result += i
    for i in kwargs.values():
        result += i
    return result


if __name__ == '__main__':
    res = fun(1, 2, 3, a=4, b=5)
    print(res)

这里要提别提一下如果fun为带返回值的函数,第4行fn前面的return必不可少,否则会造成print(res)的时候结果为None。原因还是因为main在执行fun(1, 2, 3, a=4, b=5)时此时的fun已经是inner了,return fn(*args, **kwargs)在本质上等价于return return fun(*args, **kwargs)(这里的fun指的是被装饰之前的fun)。
在这里插入图片描述

4. 拓展:闭包

闭包个人理解和装饰器其实就是一回事,区别在于闭包传进去的参数可以不是函数,对于接收inner对象的函数名也没有特殊要求。而装饰器要求传进去的参数必须为函数类型(就是被装饰的函数),接收inner的函数名也必须和传入的函数名相同。

下面贴一下关于闭包的确切定义:
1.在函数嵌套(函数里面再定义函数)的前提下
2.内部函数使用了外部函数的变量(还包括外部函数的参数)
3.外部函数返回了内部函数

常规思路下对方法调用的理解是:方法在被调用时入栈,执行完时出栈销毁,其中保存的变量也会随之一并销毁,但在闭包形成时,外部函数在调用完成并返回内部函数对象时,检测到内部函数使用了自己的局部变量,便会将自己所被使用到的局部变量与内部对象绑定在一起返回。

闭包的一个简单实例,实现求一个数的n次方:

# 定义一个闭包
def outer(n):
    def inner(num):
        return num ** n
    return inner


if __name__ == '__main__': 
    fun1 = outer(3)         # 求3次方
    res1 = fun1(4)          # 求4的3次方
    print(f"res1:{res1}")
    
    fun2 = outer(2)         # 求2次方
    res2 = fun2(8)          # 求8的二次方
    print(f"res2:{res2}")

在这里插入图片描述

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:32:27  更:2022-04-22 18:34:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:01:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码