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

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

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

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

def funA(fun):
print (fun()) def funB():
print ('B')
return funA(funB)
-----------------------------
>>>
B

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

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

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

而修饰器的作用:

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

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

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

def funA(fun):
print ('funA') @funA
def funB():
print ('B')
return
---------------------------
>>>
funA

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

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

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

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

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

第二次修改:

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

def w1(func):
print('正在装饰')
def cou():
print('')
func()
return cou @w1
def f1():
print('') >>>正在装饰

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

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

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

两层装饰: 例子:

def w1(func):
print("---正在装饰1----")
def inner():
print("---1111111111----")
func()
return inner def w2(func):
print("---正在装饰2----")
def inner():
print("---2222222222----")
func()
return inner @w1
@w2
def f1():
print("---f1---") >>>---正在装饰2----
---正在装饰1----

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

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

---正在装饰2----
---正在装饰1----
-------
-------
---f1---

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

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

def w1(func):
print("---正在装饰1----")
def inner(*args, **kwargs):
print("---1111111111----")
func(*args, **kwargs)
return inner @w1
def f1(a):
print("---%d---" % a)
f1() >>>---正在装饰1----
-------
------

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

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

def w1(func):
print("---正在装饰1----")
def inner(*args, **kwargs):
print("---1111111111----")
result = func(*args, **kwargs) # <----------------------
return result # <----------------------
return inner @w1
def f1(a):
print("---%d---" % a)
return
a = f1()
print(a) >>>---正在装饰1----
-------
------

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

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

def w1():
print("---正在装饰1----")
def inner(func):
print("---1111111111----")
return inner @w1()
def f1():
print("---f1---") >>>---正在装饰1----
-------

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

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

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

def a1(nihao):
def w1(func):
print("---正在装饰1----")
def inner():
print("---1111111111----%s" % nihao)
func()
return inner
return w1 @a1('hello~')
def f1():
print("---f1---") >>>---正在装饰1----

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

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

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

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

>>>
---正在装饰1----
-------hello~
---f1---

Python_@修饰器(装饰器)的理解的更多相关文章

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

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

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

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

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

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

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

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

  5. python__高级 : @修饰器(装饰器)的理解

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

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

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

  7. python_如何定义装饰器类?

    案例: 实现一个能将函数调用信息记录到日志的装饰器 需求: 把每次函数的调用时间,执行时间,调用次数写入日志 可以对被装饰函数分组,调用信息记录到不同日志 动态修改参数,比如日志格式 动态打开关闭日志 ...

  8. python_如何修改装饰器中参数?

    案例: 为分析程序内哪些函数执行时间开销较大,我们需定义一个带timeout参数的装饰器 需求: 统计被装饰函数的运行时间 时间大于timeout时,将此次函数调用记录到log日志中 运行时可以修改t ...

  9. 理解Python装饰器

    装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权 ...

随机推荐

  1. ROS(indigo)ABB机器人MoveIt例子

    ROS(indigo)ABB机器人例子 参考网址: 1  http://wiki.ros.org/Industrial 2  http://wiki.ros.org/abb 3  https://gi ...

  2. 05 Activity 跳转传值

    第一个Activity: package com.fmyboke; import java.io.Serializable; import java.util.ArrayList; import ja ...

  3. 人类创造未来的思想先锋:这些 TED 演示深深震撼着我们

    今年亮点之一是谷歌创始人拉里佩奇的演讲.他有一个核心观点:特别成功的公司,是那些敢于想象未来,并付出行动创造未来的公司.这听上去是老生常谈,但又确实是个真理.他实际上想说预测未来的最好方式就是创造它, ...

  4. iOS 屏幕方向

    参考文章:http://www.tuicool.com/articles/e2q6zi 一般的应用,只会支持竖屏正方向一个方向,支持多个屏幕方向的应用还是比较少的. 当时也没搞明白,所以直接就设置了正 ...

  5. 07_NoSQL数据库之Redis数据库:Redis的高级应用之事务处理、持久化操作、pub_sub、虚拟内存

     事务处理 Redis对事务的支持目前还比较简单.Redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令.当一个client在一个连接中发出mul ...

  6. 初识WCF之使用配置文件部署WCF应用程序

    二月份的开头,小编依旧继续着项目开发之路,开始接触全新的知识,EF,WCF,MVC等,今天小编来简单的总结一下有关于WCF的基础知识,学习之前,小编自己给自己提了两个问题,WCF是什么?WCF能用来做 ...

  7. iOS中 加强日志输出 开发技术总结

    对于那些做后端开发的工程师来说,看LOG解Bug应该是理所当然的事,但我接触到的移动应用开发的工程师里面,很多人并没有这个意识,查Bug时总是一遍一遍的试图重现,试图调试,特别是对一些不太容易重现的B ...

  8. 批量替换数据库中所有用户数据表中字段数据类型为char和varchar到nvarchar的脚本

    解决问题:字段类型为char的总是占用指定字节长度(末尾好多空白符号),varchar数据类型长度一个汉字占2个字节,内容存储为中文的字段个人建议全部使用nvarchar. 操作说明:打开SQL Se ...

  9. javascript之DOM编程实现城市的联动框

    需求;用一张图片表示. 分析: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  10. 4.2、Libgdx各个模块概览

    (原文:http://www.libgdx.cn/topic/34/4-2-libgdx%E5%90%84%E4%B8%AA%E6%A8%A1%E5%9D%97%E6%A6%82%E8%A7%88) ...