装饰器其实一直是我的一个"老大难"。这个知识点就放在那,但是拖延症。。。

其实在平常写写脚本的过程中,这个知识点你可能用到不多

但在面试的时候,这可是一个高频问题。

一、什么是装饰器

所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。

这一句话理解起来可能没那么轻松,那先来看一个"傻瓜"函数。

放心,绝对不是"Hello World"!

def hello():    print("你好,装饰器")

怎么样,没骗你吧? 哈哈,这个函数不用运行相信大家都知道输出结果:"你好,装饰器"。

那如果我想让hello()函数再实现个其他功能,比如多打印一句话。

那么,可以这样"增强"一下:

def my_decorator(func):    def wrapper():        print("这是装饰后具有的新输出")        func()    return wrapperdef hello():    print("你好,装饰器")hello = my_decorator(hello)hello()

运行结果:

这是装饰后具有的新输出你好,装饰器[Finished in 0.1s]

很显然,这个"增强"没啥作用,但是可以帮助理解装饰器。

当运行最后的hello()函数时,调用过程是这样的:

  1. hello = my_decorator(hello)中,变量hello指向的是my_decorator()
  2. my_decorator(func)中返回的wrapper(),传参是hello,因此又会调用到原函数hello()
  3. 于是乎,先打印出了wrapper()函数里的,然后才打印出hello()函数里的

那上述代码里的my_decorator()就是一个装饰器。
它改变了hello()的行为,但是并没有去真正的改变hello()函数的内部实现。

但是,python一直以"优雅"被人追捧,而上述的代码显然不够优雅。

二、优雅的装饰器

所以,想让上述装饰器变得优雅,可以这样写:

def my_decorator(func):    def wrapper():        print("这是装饰后具有的新输出")        func()    return wrapper@my_decoratordef hello():    print("你好,装饰器")hello()

这里的@my_decorator就相当于旧代码的hello = my_decorator(hello),@符号称为语法糖。

那如果还有其他函数也需要加上类似的装饰,直接在函数的上方加上@my_decorator就可以,大大提高函数
的重复利用与可读性。

def my_decorator(func):    def wrapper():        print("这是装饰后具有的新输出")        func()    return wrapper@my_decoratordef hello():    print("你好,装饰器")@my_decoratordef hello2():    print("你好,装饰器2")hello2()

输出:

这是装饰后具有的新输出你好,装饰器2[Finished in 0.1s]

三、带参数的装饰器

1. 单个参数

上面的只是一个非常简单的装饰器,但是实际场景中,很多函数都是要带有参数的,比如hello(people_name)。

其实也很简单,要什么我们就给什么呗,直接在对应装饰器的wrapper()上,加上对应的参数:

def my_decorator(func):    def wrapper(people_name):        print("这是装饰后具有的新输出")        func(people_name)    return wrapper@my_decoratordef hello(people_name):    print("你好,{}".format(people_name))hello("张三")

输出:

这是装饰后具有的新输出你好,张三[Finished in 0.1s]

2. 多个参数

但是还没完,这样虽然简单,但是随之而来另一个问题:因为并不是所有函数参数都是一样的,
当其他要使用装饰器的函数参数不止这个一个肿么办?比如:

@my_decoratordef hello3(speaker, listener):    print("{}对{}说你好!".format(speaker, listener))

没关系,在python里,*args和**kwargs表示接受任意数量和类型的参数,所以我们可以这样
写装饰器里的wrapper()函数:

def my_decorator(func):    def wrapper(*args, **kwargs):        print("这是装饰后具有的新输出")        func(*args, **kwargs)    return wrapper@my_decoratordef hello(people_name):    print("你好,{}".format(people_name))@my_decoratordef hello3(speaker, listener):    print("{}对{}说你好!".format(speaker, listener))hello("老王")print("------------------------")hello3("张三", "李四")

同时运行下hello("老王"),和hello3("张三", "李四"),看结果:

这是装饰后具有的新输出你好,老王------------------------这是装饰后具有的新输出张三对李四说你好![Finished in 0.1s]

3. 自定义参数

上面2种,装饰器都是接收外来的参数,其实装饰器还可以接收自己的参数。
比如,我加个参数来控制下装饰器中打印信息的次数:

def count(num):    def my_decorator(func):        def wrapper(*args, **kwargs):            for i in range(num):                print("这是装饰后具有的新输出")                func(*args, **kwargs)        return wrapper    return my_decorator@count(3)def hello(people_name):    print("你好,{}".format(people_name))hello("老王")

注意,这里count装饰函数中的2个return.
运行下,应该会出现3次:

这是装饰后具有的新输出你好,老王这是装饰后具有的新输出你好,老王这是装饰后具有的新输出你好,老王[Finished in 0.1s]

4. 内置装饰器@functools.wrap

现在多做一步探索,我们来打印下下面例子中的hello()函数的元信息:

def my_decorator(func):    def wrapper(*args, **kwargs):        print("这是装饰后具有的新输出")        func(*args, **kwargs)    return wrapper@my_decoratordef hello(people_name):    print("你好,{}".format(people_name))print(hello.__name__) #看下hello函数的元信息

输出:

wrapper

这说明了,它不再是以前的那个 hello() 函数,而是被 wrapper() 函数取代了。

如果我们需要用到元函数信息,那怎么保留它呢?这时候可以用内置装饰器@functools.wrap。

import functoolsdef my_decorator(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print("这是装饰后具有的新输出")        func(*args, **kwargs)    return wrapper@my_decoratordef hello(people_name):    print("你好,{}".format(people_name))print(hello.__name__)

运行下:

hello[Finished in 0.1s]

好记性不如烂笔头,写一下理解一下会好很多。
下面还分享类的装饰器,以及装饰器所用场景。

最后,小编想说:我是一名python开发工程师,整理了一套最新的python系统学习教程,想要这些资料的可以关注私信小编“01”即可(免费分享哦)希望能对你有所帮助。

python重复字符串n次_python装饰器听了N次也没印象,读完这篇你就懂了相关推荐

  1. python中装饰器的作用_Python装饰器详解,详细介绍它的应用场景

    装饰器的应用场景附加功能 数据的清理或添加:函数参数类型验证 @require_ints 类似请求前拦截数据格式转换 将函数返回字典改为 JSON/YAML 类似响应后篡改为函数提供额外的数据 moc ...

  2. python装饰器与闭包_Python 装饰器和闭包

    Python 装饰器和闭包 装饰器是 Python 中常见的语法糖,这篇文章讲了闭包和装饰器的原理,并且分析了函数中变量的作用域,以及尝试总结了常见的坑. 装饰器基础 首先来看看装饰器的定义:装饰器本 ...

  3. python装饰器参数讲解_python装饰器的详细解析

    写在前面: python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于它的 ...

  4. python装饰器函数执行后日志_python 装饰器理解

    在理解装饰器之前,先应该对闭包有个概念:所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时得到的对象,它的主要作用是封存上下文.这一特性可以巧妙的被用于现有函数的包装,从而为现有函数添加功 ...

  5. [python 进阶] 第7章 函数装饰器和闭包

    文章目录 7.1 装饰器基础知识 7.2 Python何时执行装饰器 7.3 使用装饰器改进"策略" 7.4 变量作用域(global) 备注 -比较字节码(暂略) 7.5 闭包 ...

  6. Python小知识点(3)--装饰器

    Python小知识点(3)--装饰器 (1)装饰器含参数,被装饰函数不含(含)参数 实例代码如下: import time # 装饰器函数 def wrapper(func):def done(*ar ...

  7. python四大高阶函数_详谈Python高阶函数与函数装饰器(推荐)

    一.上节回顾 Python2与Python3字符编码问题,不管你是初学者还是已经对Python的项目了如指掌了,都会犯一些编码上面的错误.我在这里简单归纳Python3和Python2各自的区别. 首 ...

  8. python 类的使用(5)之类装饰器(类的装饰器和类作为装饰器)

    在阅读博客中,发现了类装饰器的存在,由于之前就在写类相关的专栏,这次就赶紧补上之前的内容啦.类装饰器这个词是有歧义的,因为类本身可以作为装饰器,一个类也可以被函数装饰器所装饰.今天就简单介绍一下这两种 ...

  9. python中的装饰器怎么运行_Python 装饰器入门(上)

    翻译前想说的话: 这是一篇介绍python装饰器的文章,对比之前看到的类似介绍装饰器的文章,个人认为无人可出其右,文章由浅到深,由函数介绍到装饰器的高级应用,每个介绍必有例子说明.文章太长,看完原文后 ...

最新文章

  1. MapReduce Java API-使用Partitioner实现输出到多个文件
  2. ubuntu 16.04更新软件源
  3. SpringCloud教程- 路由网关Zuul (SpringCloud版本Greenwich.SR4)
  4. .NET实现SOA(1)
  5. python导入机制及importlib模块
  6. [html] 写一个左中右的满屏布局,左右固定220px,中间自适应并且要优先加载
  7. UVA - 1347
  8. linux视频字幕下载工具,Linux中编辑视频字幕
  9. Android中动态调整ImageView的宽高比
  10. 通过ip如何免费反查域名?
  11. GIT LFS 原理杂谈
  12. 如何下载东四街道卫星地图高清版大图
  13. Springboot集成Hadoop+Hbase实现企业能源消耗监测大数据分析系统
  14. vue3 图片懒加载的实现
  15. 车辆网络安全ISO/SAE 21434解读(十)TARA分析
  16. 组织敏捷程序:第2部分,用于管理敏捷程序的网络
  17. 编码理解 | 卷积的实现和卷积神经网络
  18. android wcf 上传文件,第二篇 ( wcf 与 android 图片上传下载)
  19. Ad Hoc网络路由协议
  20. oracle001658,ORACLE error 1658,该如何解决

热门文章

  1. 统计1000个10以内随机数随机数出现的个数
  2. 【算法】一个简单的决策树(DT)原理
  3. [云炬创业基础笔记]第五章创业机会评估测试8
  4. 云炬Android开发笔记 9主界面-通用底部导航设计与一键式封装
  5. rabbitmq 延迟队列_框架系列|中间件RabbitMQ必看17道面试题
  6. Go进阶(3): 函数+闭包+defer
  7. Adaboost(自适应提升树)算法原理
  8. [骨科手术导航]2D/3D医学图像配准研究_罗博博_南方科技大学
  9. Windows 外壳扩展编程入门实例
  10. 如何用javascript获取文本框,下拉框,单选框的对应值或者将值赋给它们?雪原虎 发布于:2007-10-22 00:32