以下是第一次了解的时候写的东西,有的地方理解不正确,虽已改正但是太片面,请直接看下面第二次修改加上的内容.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能.

装饰器的作用就是为已经存在的对象添加额外的功能。

  1. def funA(fun):
  2. print (fun())
  3.  
  4. def funB():
  5. print ('B')
  6. return
  7.  
  8. funA(funB)
  9. -----------------------------
  10. >>>
  11. B

可以看出,这个程序的运行过程为:

1.执行函数funA,把funB当作参数传进去, print(fun()) 这一句 执行了 funB, 然后打印 'B' , 返回 1

2. print(fun()) 这一句把 返回的 1 打印出来

而修饰器的作用:

  1. def funA(fun):  #函数本身也是对象,所以可以将函数作为参数传入另一函数并进行调用,而funB是有返回值的,所以结果输出了返回值1.(个人理解)
  2. print (fun())
  3.  
  4. @funA
  5. def funB():
  6. print ('B')
  7. return
  8. ----------------------
  9. >>>
  10. B

作用相当于 funB = funA(funB),不过只能放在一个函数或者类定义之前

需要注意的是,如果funB在funA里没用被调用的话,那funB是不会被执行的,如:

  1. def funA(fun):
  2. print ('funA')
  3.  
  4. @funA
  5. def funB():
  6. print ('B')
  7. return
  8. ---------------------------
  9. >>>
  10. funA

可以看出,只执行了funA而funB没有被执行,因为print('B')并没有被打印出来.

ps:如果funA不加参数的话,比如直接 def funA(): 这样定义,他是会报错的:

  1. @funA
  2. TypeError: funA() takes positional arguments but was given

大意是@funA中的funA必须要给他提供一个参数,但是你给了0个.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第二次修改:

第一次了解的是一些浅层次的东西,把它深入一下,看个例子:

  1. def w1(func):
  2. print('正在装饰')
  3. def cou():
  4. print('')
  5. func()
  6. return cou
  7.  
  8. @w1
  9. def f1():
  10. print('')
  11.  
  12. >>>正在装饰

可以看出,装饰器 @w1 这一行,其实在函数没有被调用之前已经执行了, 这一句就等于  f1=w1(f1)  所以 w1 函数已经被调用了,返回的是 cou函数的引用,

所以说如果再调用 f1() ,其实执行的是 cou() ,而真正的 f1 函数的引用现在正被保存在 w1 函数中的 func参数里面,

(这儿可以当作闭包的一个表现,即当函数中有东西外边还有引用指向它的时候,它并不会立即回收,而是保存了这个函数的空间)

两层装饰: 例子:

  1. def w1(func):
  2. print("---正在装饰1----")
  3. def inner():
  4. print("---1111111111----")
  5. func()
  6. return inner
  7.  
  8. def w2(func):
  9. print("---正在装饰2----")
  10. def inner():
  11. print("---2222222222----")
  12. func()
  13. return inner
  14.  
  15. @w1
  16. @w2
  17. def f1():
  18. print("---f1---")
  19.  
  20. >>>---正在装饰2----
  21. ---正在装饰1----

从运行结果可以看出,首先调用装饰器w2,再调用装饰器w1,也就是说 运行到 @w1 这一行,因为在它下面的并不是一个函数,所以w1先暂停,先调用w2,w2装饰完成之后,返回的是w2 的 inner 函数的引用,

w1 再开始对 w2 的inner 函数进行装饰. 最后返回的是w1 的 inner 函数.如果最后调用 f1()  那么运行结果为:

  1. ---正在装饰2----
  2. ---正在装饰1----
  3. -------
  4. -------
  5. ---f1---

因为 这个时候调用 f1() 其实 调用的是 w1的 inner 函数,所以首先打印 --11111--- ,然后 执行 func() 这个func() 也就是 w2 的inner, 所以再打印 ---222222----, 下一句 fun() 才是真正的 f1() 函数,打印 ---f1---

装饰有参数的函数: 被装饰的函数有参数的话,可以这样:

  1. def w1(func):
  2. print("---正在装饰1----")
  3. def inner(*args, **kwargs):
  4. print("---1111111111----")
  5. func(*args, **kwargs)
  6. return inner
  7.  
  8. @w1
  9. def f1(a):
  10. print("---%d---" % a)
  11. f1()
  12.  
  13. >>>---正在装饰1----
  14. -------
  15. ------

在 inner 函数里面加上 接受无名参数和关键字参数,然后 func(*args, **kwargs) 把接收到的参数原封不动的传回 f1 函数里面去,这样 f1 无论有多少个参数,都可以给他传回去.

那么,如果被装饰的函数有返回值,同样,在 inner里面把函数返回的东西用个变量保存起来,然后 在inner 里面return 即可:

  1. def w1(func):
  2. print("---正在装饰1----")
  3. def inner(*args, **kwargs):
  4. print("---1111111111----")
  5. result = func(*args, **kwargs) # <----------------------
  6. return result # <----------------------
  7. return inner
  8.  
  9. @w1
  10. def f1(a):
  11. print("---%d---" % a)
  12. return
  13. a = f1()
  14. print(a)
  15.  
  16. >>>---正在装饰1----
  17. -------
  18. ------

可以看出 a 成功保存了返回的结果 456 .

如果,对装饰器进行调用,如 @w1() 后面带个括号, 结果会怎样:

  1. def w1():
  2. print("---正在装饰1----")
  3. def inner(func):
  4. print("---1111111111----")
  5. return inner
  6.  
  7. @w1()
  8. def f1():
  9. print("---f1---")
  10.  
  11. >>>---正在装饰1----
  12. -------

可以看出,虽然没有调用f1,但是竟然连里面的inner函数也被执行了一遍,因为输出了 ---111111111111-----,这说明,如果 @w1() 这样用 ,那么它首先会 把 w1() 函数执行一遍 , 这个时候返回的是 inner 函数的引用,

那么,@w1() 就变成了 @inner 这个时候 再把f1传到了inner函数里面开始进行装饰 所以 inner 函数被执行,

利用这个特点,可以在 装饰器中带有参数 ,只不过为了防止调用,需要在外面再加上一层:

  1. def a1(nihao):
  2. def w1(func):
  3. print("---正在装饰1----")
  4. def inner():
  5. print("---1111111111----%s" % nihao)
  6. func()
  7. return inner
  8. return w1
  9.  
  10. @a1('hello~')
  11. def f1():
  12. print("---f1---")
  13.  
  14. >>>---正在装饰1----

过程 1. 首先执行 a1('hello~')   a1里面用 nihao 这个变量保存传递的参数,返回的是 w1 的引用

2. 装饰器那一行 变成了 @w1 ,然后把 f1 传递进去,调用 w1 开始进行装饰

  3. 装饰完成后 返回的 是 inner 的引用 所以 现在 f1 = inner

如果调用 f1() 则正常执行,还可以在 inner 中把传递进去的参数打印出来:

  1. >>>
  2. ---正在装饰1----
  3. -------hello~
  4. ---f1---

python__高级 : @修饰器(装饰器)的理解的更多相关文章

  1. python__高级 : 类当作装饰器

    类在创建对象时,会调用 __init__ 初始化一些东西 , 然后 如果类中定义了 __call__ 方法,可以直接用  对象()  这种方法调用,所以可以用类来装饰函数: class Test(ob ...

  2. Python - 三大器 迭代器,生层器,装饰器

    目录 Python - 三大器 迭代器,生层器,装饰器 一. 容器 二. 可迭代对象(iterable) 三. 迭代器 四. 生成器 五. 装饰器 1. 定义 六. 闭包 Python - 三大器 迭 ...

  3. python 带参与不带参装饰器的使用与流程分析/什么是装饰器/装饰器使用注意事项

    一.什么是装饰器 装饰器是用来给函数动态的添加功能的一种技术,属于一种语法糖.通俗一点讲就是:在不会影响原有函数的功能基础上,在原有函数的执行过程中额外的添加上另外一段处理逻辑 二.装饰器功能实现的技 ...

  4. typescript装饰器 方法装饰器 方法参数装饰器 装饰器的执行顺序

    /* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...

  5. typescript装饰器定义 类装饰器 属性装饰器 装饰器工厂

    /* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...

  6. Python_@修饰器(装饰器)的理解

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的作用就是为已经存在的对象添加额外的功能. def funA(fun): print (fun( ...

  7. Decorator [ˈdekəreɪtə(r)] 修饰器/装饰器 -- 装饰模式

    装饰模式 -- 原先没有,后期添加的属性和方法 修饰器(Decorator)是一个函数,用来修饰类的行为.这是ES7的一个提案,目前Babel转码器已经支持. 需要先安装一个插件: npm insta ...

  8. Python学习之路day4-函数高级特性、装饰器

    一.预备知识 学习装饰器需理解以下预备知识: 函数即变量 函数本质上也是一种变量,函数名即变量名,函数体就变量对应的值:函数体可以作为值赋给其他变量(函数),也可以通过函数名来直接调用函数.调用符号即 ...

  9. python高级编程之装饰器04

    from __future__ import with_statement # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrat ...

随机推荐

  1. 什么是NIO2

    NIO2I/O发展历史Java1.0-1.3在Java的早期版本中,没有完整的I/O支持,在开发过程中需要解决以下问题:1)没有数据缓冲区或者NIO的通道概念,需要编程人员处理底层细节.2)I/O是受 ...

  2. hystrix应用介绍(二)

    上篇博客中讲了hystrix在公司中的一些应用场景,由于保密的原因没办法贴出优化的代码,这里专门写一篇hystrix代码的demo,供大家在使用的过程中快速上手 Hystrix有两个请求命令 Hyst ...

  3. springboot2.x如何配置全局自定义异常

    为什么要捕获异常? 我们开发中,经常运行时,代码会报错,这时候我们有可能抛出异常,而不是用try..catch来解决.而且现在前后端分离,如果不捕获异常的话,前端那边的人估计会被报的错搞得焦头烂额的. ...

  4. Linux pptpd 的 iptables 包过滤设置

    用Centos架设了一台pptpd vpn服务器,信息如下: 服务器IP 192.168.100.1 /24 网关 192.168.100.254(NAT防火墙,将 <外网IP>:1723 ...

  5. HBuilder中改造console.info

    HBuilder的js中console.info只会输出头一个参数,与谷歌浏览器行为不符合.让人很不习惯. 于是,对其改造一番. window.console.print=window.console ...

  6. java右移>> 无符号右移>>>

    >>>是无符号右移,在高位补零 >>是带符号的右移,如果是正数则在高位补零,负数则补1 int a = -1; System.out.println(a>>1 ...

  7. http:origin,referer和host区别

    发起一个ajax请求时,request header里面有三个属性会涉及请求源信息.前端可能用不到这些值,但是,后台业务系统会比较关心它们,场景可能有: 处理跨域请求时,必须判断来源请求方是否合法:后 ...

  8. 怎样解决putty终端乱码的方法

    原文地址:https://jingyan.baidu.com/article/3aed632e5f00ae701080913a.html?qq-pf-to=pcqq.c2c 终端输入:echo $LA ...

  9. mongoDB基础知识(一)

    mongoDB是一个基于分布式文件存储的数据库,介于关系型数据库和非关系型数据库之间,在非关系型数据库中功能最丰富, 最像关系型数据库.数据结构松散,类似于json的bson格式,可以存储比较复杂的数 ...

  10. 01、Scala介绍与安装

    01.Scala介绍与安装 1.1 Scala介绍 Scala是对java语言脚本化,特点是就是使不具备脚本化的java语言能够采用脚本化方式来使用,使其具有脚本语言简单.所见即所得的特点,并且编程效 ...