python装饰器的作用就是在不改变原有函数结构的情况下给该函数增加一个新功能,就是不入侵到原来函数里面修改代码给其增加一个新功能

先看代码

def out(fn):
def inner(*args, **kwargs):
print("这个是个装饰器,是用来装饰其他函数用的")
ret = fn(*args, **kwargs)
print("******************")
return ret
return inner

上面是个装饰器函数

下面是被装饰的函数

def test(name):
print("这个是fn函数,是被装饰的")
return name

怎么调用呢?

常规方法是这样,把下面的test函数以参数方式传入到上面的装饰器函数,也就是下面这样的方式

foo = out(test)
print(foo("Bob"))
#我们看下执行结果
这个是个装饰器,是用来装饰其他函数用的
这个是fn函数,是被装饰的
******************
Bob #在没有改变test函数代码情况下给test函数增加了新功能

但是以上的调用方式太过于麻烦,有没有简单点的,答案是有的,就是用以下方式调用

@out
def test(name):
print("这个是fn函数,是被装饰的")
return name
##上面的@out方式在python中是叫做语法糖的方式,其实就等价于以下的调用方式
#####
test = out(test) ##==>把out(test)的返回值再赋值给test,想想out(test)的返回值是什么?对了,是inner函数,所以此时test 也就是inner函数了
####
print(test("Bob")) ###==>同理,这里打印出来是是inner函数的返回值,以及inner函数的print函数所打印出的东西,由于Inner函数同时也返回了test函数的返回值,所以就达到了,在不改变test函数情况下,给test函数增加了新功能

我们来看个完整的代码块,以及执行结果

def out(fn):
def inner(*args, **kwargs):
print("这个是个装饰器,是用来装饰其他函数用的")
ret = fn(*args, **kwargs)
print("******************")
return ret
return inner @out
def test(name):
print("这个是fn函数,是被装饰的")
return name
@out
def test_other(name):
print("这是另外一个被装饰的函数")
return name print(test("Bob"))
print("********我是华丽的分割线******")
print(test_other("Joke")) ########执行结果如下########### 这个是个装饰器,是用来装饰其他函数用的
这个是fn函数,是被装饰的
******************
Bob
********我是华丽的分割线******
这个是个装饰器,是用来装饰其他函数用的
这是另外一个被装饰的函数
******************
Joke

看到了吧,两个函数都被正确的装饰了

接下来我们看点有趣的东西,这是我忽然想到的

先看代码块

def out(args):
def inner(fn):
print("这个是个装饰器,是用来装饰其他函数用的")
ret = fn(args)
print("******************")
return ret
return inner def test(name):
print("这个是fn函数,是被装饰的")
return name foo = out("Joke")
print(foo(test)) #####看下执行结果#####
这个是个装饰器,是用来装饰其他函数用的
这个是fn函数,是被装饰的
******************
Joke

是不是很神奇啊,out函数接收常规参数,inner函数接收函数参数也就是func参数

首先 foo = out("Joke"),先传入一个常规str值

然后 print(foo(test)) 打印出foo的返回值,这里的逻辑很重要我们来捋下==>>

foo = out("Joke")等价于把out("Joke")返回值赋给foo,那么这时候foo就等价于inner函数,只是这个args函数给传进去,但是还没使用,你给函数传参是一回事,你用与不用又是另一回事,对不对?所以这里没什么可纠结的吧,然后我们print(foo(test))就等价于把test函数以参数方式传入到inner函数里面,由于你已经传入到一个args了,所以了test函数是可以拿到这个参数的,不明白的建议看下函数的作用域这块,ret = fn(args) 就等价于test(name)明白了吧,最后return ret就得到了test(name),这和上面的装饰器实现方式其实是一致的,只是参数位置调换了而已,装饰器的out的参数是函数,inner参数是常规str参数,这个正好对换位置了,传参方式也相应改变了,我不知道这个有什么用,但是只是想试试,那么我们还能用@out方式来装饰吗,试试就知道了

def out(args):
def inner(fn):
print("这个是个装饰器,是用来装饰其他函数用的")
ret = fn(args)
print("******************")
return ret
return inner @out
def test(name):
print("这个是fn函数,是被装饰的")
return name
print(test("Bob")) ###来看下结果###
这个是个装饰器,是用来装饰其他函数用的
Traceback (most recent call last):
File "E:/python_learn/装饰器.py", line 13, in <module>
print(test("Bob"))
File "E:/python_learn/装饰器.py", line 4, in inner
ret = fn(args)
TypeError: 'str' object is not callable
最后一句告诉你str是不能被调用的,看来更换参数位置后,装饰器也不能这样调用了,这样有助于大家更快理解装饰器。

python 装饰器的理解以及类装饰器的更多相关文章

  1. python 描述符 上下文管理协议 类装饰器 property metaclass

    1.描述符 #!/usr/bin/python env # coding=utf-8 # 数据描述符__get__ __set__ __delete__ ''' 描述符总结 描述符是可以实现大部分py ...

  2. Java类载入器(二)——自己定义类载入器

      用户定制自己的ClassLoader能够实现以下的一些应用: 自己定义路径下查找自己定义的class类文件,或许我们须要的class文件并不总是在已经设置好的Classpath以下,那么我们必须想 ...

  3. python高级 之(二) --- 类装饰器

    装饰器-初级 在不改变原有函数逻辑功能的基础上,为函数添加新的逻辑功能.使代码可读性更高.结构更加清晰.冗余度更低 简介 """ 闭包: 函数嵌套的格式就是闭包.写装饰器 ...

  4. python装饰器2:类装饰器

    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 本文是装饰器相关内容的第二篇,关于类装饰器. "类装饰器"有两种解读方式:用来装饰类的装饰器:类作为装饰器装饰其它东西.你 ...

  5. 黑马程序猿——Java中的类载入器

    ------- android培训.java培训.期待与您交流! -------- 类载入器 Java虚拟机中能够安装多个类载入器,系统默认三个主要类载入器,每一个类负责载入特定位置的类: BootS ...

  6. Jboss7类载入器

    1. 类载入器理论知识介绍 类载入器基于Jboss Module,代替了层次类载入环境,避免了当类存在多个版本号时,导致类载入错误. 类载入是基于模块的.必须显示的定义模块依赖.部署也是模块化的,假设 ...

  7. java类载入器——ClassLoader

    Java的设计初衷是主要面向嵌入式领域,对于自己定义的一些类,考虑使用依需求载入原则.即在程序使用到时才载入类,节省内存消耗,这时就可以通过类载入器来动态载入. 假设你平时仅仅是做web开发,那应该非 ...

  8. 转发对python装饰器的理解

    [Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考   原文  http://blog.csdn.net/sxw3718401/article/details/3951958 ...

  9. python中对变量的作用域LEGB、闭包、装饰器基本理解

    一.作用域 在Python程序中创建.改变.查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域.python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量 ...

随机推荐

  1. 强大的拖拽组件:React DnD 的使用

    强大的拖拽组件:React DnD 的使用 react.js 10.6k 次阅读  ·  读完需要 25 分钟 17 文章首发我的个人blog : 原文链接 学习 React DnD 的最初原因是阅读 ...

  2. python+flask开发小白第二天

    使用VSCode编译python web页面 1.先从最基础的说起吧,关于VSCode的使用: 运行python程序与运行java,c,c++程序一样,需要新建一个文件,第一个文件建议不要新建在本地的 ...

  3. 关于Jordan标准形

    [转载请注明出处]http://www.cnblogs.com/mashiqi 2017/06/25 设$A$是$n$维线性空间$V$上的线性变换,它的特征值与相应的代数重数分别为$\lambda_i ...

  4. IDEA将web项目打成war包

    非Maven项目打包方式    按ctrl+滚动鼠标滚轮就能放大浏览器看图片了.或者将图片拖到新窗口打开. 然后点击OK,然后build一下.然后去classes文件夹下面找就能找到打成war包的项目 ...

  5. 由于找不到 opencv_world320.dll,无法继续执行代

    首先找到自己软件安装(解压)的路径openCV (安装(解压)目录\opencv\build\x64\vc14\bin) 我的安装(解压)目录是:F:\OpenCV\Three320\opencv\b ...

  6. 关于js的对象创建方法(简单工厂模式,构造函数模式,原型模式,混合模式,动态模式)

    // 1.工厂方式创建对象:面向对象中的封装函数(内置对象) 简单来说就是封装后的代码,简单的工厂模式是很好理解的,关于它的作用,就是利用面向对象的方法,把一些对象封装,使一些占用空间多的,重复的代码 ...

  7. python写service时全局变量问题

    在尝试用flask写service的过程中,我发现全局变量使用虽然很方便,但其实是很冒险的. 本次我使用的是声明global变量的方式,如果作为本地的单次使用的程序来说,确实没有问题并且很好用,对于竞 ...

  8. 看淘宝营销api 文档有感

    total: use appkey & secrect variance naming rule 提供沙箱环境 使用api gateway 使用rest(但返回结果包裹了 isp.thread ...

  9. Java 中int、String的类型转换

    int -> String int i=12345;String s="";第一种方法:s=i+"";第二种方法:s=String.valueOf(i); ...

  10. MySQL Execution Plan--NOT IN查询

    在某系统中想使用NOT IN子查询进行数据过滤,SQL为: SELECT * FROM TB001 AS T1 DAY) AND T1.BATCH_NO NOT IN(SELECT BATCH_NO ...