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. Hbuilder护眼主题分享

    sublime还有webstorm有很多主题,但是Hbuilder就相对较少,或者直接说基本没什么主题,在网上搜索了很久也很少有Hbuilder的主题分享,于是就自己取色调了一个仿的护眼主题来分享一下 ...

  2. j教你如何用erlang-tuple

    元组是用来保存一组数据元素的复合数据类型,其中数据元素是要求为erlang的数据类型,单不一定要是相同的类型,元组使用封闭的花括号{}来定义,里面的元素有逗号隔开. 例如: 1> {1,2,3} ...

  3. cocos2dx解决中文乱码方法

    使用plist文件,优点方便做多国语言支持~也不用去做编码转换 1.Resource目录下新建text.plist文件,内容格式如下 <?xml version="1.0" ...

  4. LADP(Lightweight Directory Access Protocol)轻量目录访问协议~小知识

    What is LDAP and how does it work(implementation)? LDAP stands for “Lightweight Directory Access Pro ...

  5. h5 网络断网时,返回上一个页面 demo (与检测网络代码相结合,更直观看到结果)

    页面一: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8& ...

  6. 2018.5.2 file结构体

    f_flags,File Status Flag f_pos,表示当前读写位置 f_count,表示引用计数(Reference Count): dup.fork等系统调用会导致多个文件描述符指向同一 ...

  7. sh - 脚本学习 启动/停止/重启/部署jetty crontab

    ===============jettytest.sh ====================== #!/bin/shjettysh_path=/usr/local/jetty/bin/jetty. ...

  8. .NET平台

    .nat 是一种跨语言的平台 类跟对象回顾 由于对象归纳类 是归纳对象共性的过程 在类似的基础上  将状态和行为实体话为对象的过程称为实例话 只写属性   只包含set访问器 只读属性  只包含get ...

  9. 集合总结四(LinkedHashMap的实现原理)

    一.概述 按照惯例,先看一下源码里的第一段注释: Hash table and linked list implementation of the Map interface, with predic ...

  10. rsync的daemon模式

    官方文档:https://download.samba.org/pub/rsync/rsyncd.conf.html   1:daemon模式配置文件         rsync以daemon方式运行 ...