装饰器是程序开发的基础知识,用好装饰器,在程序开发中能够提高效率
它可以在不需要修改每个函数内部代码的情况下,为多个函数添加附加功能,如权限验证,log日志等
 
涉及点:
 
1.先梳理一下
 
>>> def fun():
    print('Fun...')
# fun 是函数
# fun() 是执行函数

#A
>>> def test():
    print(1)
>>> def test():
    print(2)
#B
>>> test()
2
>>>
 
重复定义函数不会报错
只是会让函数名指向不同的函数体
 
>>> def test():
    print('TEST')
>>> def fun():
    print('FUN')
>>> test=fun # test改变指向,指向了和fun一样的函数体
>>> test()
FUN
>>>
 
在C和C++中,会告诉你两个函数重名了,在Python中不会,会默认改变指向
 
2.开放封闭原则
开放:对扩展开发
封闭:已实现的功能代码块
1.添加新需求,最好不要改动原来的代码块,因为别处已经调用的地方可能会报错,
尽可能进行扩展
2.开发的时候,别轻易删除代码
 
3.现有fun1,fun2函数,在每次调用这两个函数时,需要进行权限验证
 
>>> def fun1():
    print('fun1')

>>> def fun2():
    print('fun2')

>>> def test(fun):
    def inner():
      print('验证')
      fun()
    return inner

>>> mytest=test(fun1)
>>> mytest()
验证
fun1
>>>
不是直接在每个需要加验证的函数里面修改,那样违反了 开放封闭 原则
而是创建一个闭包:
test的参数在内部函数中被调用,被调用时,先执行验证功能。传入的参数决定了是哪个函数
所以即可以传入fun1,也可以传入fun2
 
上面的代码虽然添加了验证功能,在不改变原有代码部分的情况下。
但每次调用不是直接调用原来的fun1 、fun2;而是调用另一个函数
现在改变一下代码:
>>> def fun1():
    print('fun1')

>>> def fun2():
    print('fun2')

>>> def test(fun):
    def inner():
      print('验证功能')
      fun()
    return inner
>>> fun1=test(fun1) # 现在能够通过原有函数名直接调用,不改变原有函数代码
>>> fun1()
验证功能
fun1
>>>
如何解释上述代码?
其实只是改变了函数名对函数体的引用
执行fun1=test(fun1)时,test中的fun参数指向了fun1的函数体。inner中,执行了fun:fun()。现在让fun1改变它的指向,让它指向inner
所以调用fun1就是调用inner函数
简言之:通过改变引用,让inner函数里面既包含新功能,也包含了旧功能
然后改变原来函数名的指向,让它指向inner函数。
但是,每次都需要这么写:fun1=test(fun1) 过于麻烦
 
4.使用语法糖:
在fun1前面加 @test 等价于 fun1=test(fun1)
>>> def test(fun):
    def inner():
      print('验证功能')
      fun()
    return inner
>>> @test
  def fun1():
    print('fun1')
>>> fun1()
验证功能
fun1
>>>
装饰器:在原有的基础上,不改动原先代码,然后添加新的功能,进行装饰(Python特有)
 
5.例子
执行结果:

这类代码应该怎么看?
如14~16行代码,把test1的功能「给」makeBold里的fn
把执行test1当成执行makeBold里的wrapped函数
 
test3添加了两个装饰器,为什么结果是<b><i>hello world-3</i></b>
6.两个装饰器装饰过程:函数test3为例
装饰器@makeBold下面是装饰器@makeItalic,需要等装饰器@makeItalic将test3进行装饰之后
返回一个新的引用,再进行装饰,所以此时装饰器@makeBold没有被执行,先执行装饰器@makeItalic
1. @makeItalic:test3=makeItalic(test3) 此时test3指向新引用,makeItalic中的wrapped
2.@makeBold:test3=makeBold(test3)此时传入的test3为@makeItalic装饰后新的test3
 

 
此时,test3指向了@makeBold中的wrapped,@makeBold中的fn指向了@makeItalic中的wrapped,@makeItalic中的fn指向了原来test3的函数体。
倒着装,顺着执行
 
7.装饰器什么时候进行装饰?
在定义的时候就进行装饰,不是等到调用才装饰
>>> def fun(fn):
    print('正在装饰...')
      def inner():
      fn()
    return inner
>>> @fun
def test():
  print('函数')
正在装饰...
>>>
 
上述情况是没有参数的情况下进行
8.现在看一下有两个参数的情况

因为(原函数)test需要两个参数,所以在调用经过装饰器装饰的test时也要传入两个参数,
这两个参数经过inner,fn传入(原函数)test的函数体
 
但是,被装饰的函数形参发生变化时,都需要改变「装饰器」函数的形参吗
9.不定参数
使用不定参数,这样不管被装饰的函数形参怎么变化,装饰器会自动匹配,只需要更改被装饰的函数的代码就可以
如:

函数test的形参由2个增加到3个:
函数test的形参由3个改为没有:
 
10.被装饰的函数有返回值的情况
打印结果:None
由于fn()返回的结果没有被inner返回,所以打印test时为None
修改:
 
执行fn()时,执行的是第10行test里面的代码,返回了一个字符串,这个字符串,也就是fn的返回值
在inner被变量rn接收,inner又返回了变量rn。
 
11.通用装饰器

运行结果:
...
None
...
test2
...
vaule: 10
...
vaule: 10 20 30
通用的装饰器,同时满足了多种函数的情况,有无参、多参、有无返回值等
当函数没有返回值时,inner函数中的变量ret接收到None
inner的形参为*args、**kwargs为不定参
 
12.带参数的装饰器
 

 

Python核心编程 | 装饰器的更多相关文章

  1. Python 元编程 - 装饰器

    Python 中提供了一个叫装饰器的特性,用于在不改变原始对象的情况下,增加新功能或行为. 这也属于 Python "元编程" 的一部分,在编译时一个对象去试图修改另一个对象的信息 ...

  2. python函数式编程-装饰器

    在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 由于函数也是一个对象,而且函数对象可以赋值给变量,所以通过变量也能调用该函数. >>> def now() ...

  3. Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器

      生成器 生成器是生成一个值的特殊函数,它具有这样的特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程 ...

  4. 面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器

    面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java中myba ...

  5. Python核心编程-闭包

    百度搜了一下闭包的概念:简而言之,闭包的作用就是在外部函数执行完并返回后,闭包使得收机制不会收回函数所占用的资源,因为内部函数的执行需要依赖外函数中的变量.这是对闭包作用的非常直白的描述,不专业也不严 ...

  6. Python深入05 装饰器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法 ...

  7. Day04 - Python 迭代器、装饰器、软件开发规范

    1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...

  8. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

  9. python核心编程--笔记

    python核心编程--笔记 的解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找pyt ...

随机推荐

  1. HBase thrift2 TIOError

    如果HBase thrift2报:"TIOError exception: Default TException", 这个可能是因为操作的表不存在,不一定是网络或磁盘操作异常. H ...

  2. 认识Hadoop

    概述 开源.分布式存储.分布式计算 大数据生态体系 特点:开源.社区活跃 囊括了大数据处理的方方面面 成熟的生态圈 推荐系统 应用场景 搭建大型数据仓库,PB级数据的存储.处理.分析.统计 日志分析 ...

  3. poj2481

    题意:给定一些线段(s, e),起点为s,终点为e,求每一段线段被多少线段包含(不包括相等) 思路:很明显的树状数组题目..但是做的时候想了挺久..(下面的x为线段起点, y为线段终点) 做法1:先对 ...

  4. hdu 4455 Substrings(计数)

    题目链接:hdu 4455 Substrings 题目大意:给出n,然后是n个数a[1] ~ a[n], 然后是q次询问,每次询问给出w, 将数列a[i]分成若干个连续且元素数量为w的集合,计算每个集 ...

  5. Windows10卡顿,磁盘 内存占用100%或比较多

    1.关闭服务:Superfetch: 2.结束antimalware service executable进程,gpedit.msc下依次点击“计算机配置/管理模板/Windows组件/Windows ...

  6. .net core 分布式配置中心

    github地址 https://github.com/wangchengqun/ratel 配置文件 数据同步端口 Server: ip: 127.0.0.1 port: 7890 浏览器访问 ht ...

  7. Python 读取文件中unicode编码转成中文显示问题

    Python读取文件中的字符串已经是unicode编码,如:\u53eb\u6211,需要转换成中文时有两种方式 1.使用eval: eval("u"+"\'" ...

  8. 将 Microsoft Excel 导入至 MySQL

    将 Microsoft Excel 导入至 MySQL 一.前言 我得到了一份 Microsoft Excel 表格,里面记录了数据信息需要导入至 SQL 数据库. 如果只是导入数据,当然用 MSSQ ...

  9. mybatis 全局配置文件

    传送门:mybatis XML 映射配置文件官方文档 配置文件中的标签顺序不能颠倒,否则会报错. <?xml version="1.0" encoding="UTF ...

  10. 开发ASP.NET MVC 在线录音录像(音视频录制并上传)

    最近有个在线招聘录音的开发需求,需要在招聘网站上让招聘者上传录音和视频. 找到两个不错的javascript开源,可以在除了IE以外的浏览器运行. https://github.com/mattdia ...