python基础-第五篇-5.3装饰器
小白发呆的看着窗外,同事们陆陆续续的地来到公司,想起算法,小白就飘飘然了。突然后面传来一声呼唤,原来是小刘!
小刘:不好意思啊!堵车了,就来晚了点,不耽误你的时间,咱们就开启的今天的培训内容吧!
小白连忙说:没事,可以开始啦!
函数内存与执行函数
小刘:那我给你看一段代码,你看看会得到什么结果
def f1():
return 'F1' x = f1()
print(x) x2 = f1
print(x2)
小白看了看,很快说出了x的输出值为‘F1’,但是看到x2这里,小白就有点想不通,小白就执行了一遍

小白还是看不懂,就问小刘这x2到底打印的是什么玩意啊?
小刘笑了笑:这可神奇了,叫做函数内存地址,看着哈,我给这这玩意加点东西
def f1():
return 'F1' x = f1()
print(x)
x2 = f1
print(x2)
ret = x2()
print(ret)
小刘:我只是把f1赋值后的x2加了个括号,最后的结果和f1函数执行的结果一样,神奇吧?
小刘:这是我画的原理图,你看看

小白若有所悟的点点头,那我这样这样做,结果那是一样一样的?
def f1():
return 'F1' x = f1()
print(x)
x2 = f1
ret = x2()
print(ret)
x3 = x2
ret2 = x3()
print(ret2)
x4 = f1
ret3 = x4()
print(ret3)
小刘:是的,你只要记住,函数名加括号就是执行函数,没加就是函数内存地址就可以了
小白点点头
当函数名也来做函数参数时
小刘:既然函数的内存地址都能赋给多个变量,那它做可以做为函数参数传入到函数体中去么??
小白含糊其辞地回来了个:应该可以吧
小刘:先给看个例子吧,你先想一下结果什么?
def login(func):
print('passed user verification...')
return func def tv():
print('welcome [%s] to tv page') tv = login(tv)
小白手停不下来,又开始画起来了

小白连忙答道:执行了login函数,打印了‘passed..ver...’,tv这个函数名指向的内存地址没有变并且tv函数不执行。
小白回答到这,又不由说到:走这么一个大弯,回来还是原样子,这个做难道有很大用处??
小刘微微一笑:你有这样的疑问!很正常,那我直接告诉你它的用处吧,在不修改源码的情况,可以增加额外的功能,比如说在基本功能上我要加个用户权限管理,login函数就是对这个进行验证的,那问你--如果上面要执行tv函数,你怎么做?
小白:简单,在下面加个调用函数--tv()
小刘点点头,那我们回到刚才那个案例上来,假如你是那基层平台的管理者,你觉得这样添加功能,你满意吗?
小白:满意!不修改源码下实现了额外的功能!
小刘:如果是我,我还是不满意,因为我要为其他的业务部门人员使用平台而考虑,以前他们只要调用tv()就行,现在要先写tv = login(tv),再写tv()才达到自己的目的,你不觉得这样添加了他们的负担吗?
小白:是啊,我怎么没想到呢?
小刘:好!冲着这点,我给到你这个方案,你看看
def login(func):
print('passed user verification...')
return func @login
def tv():
print('welcome [%s] to tv page') tv()
小刘:那我也明确告诉你,@login的作用等同于tv=login(tv),你看最终会得出什么结果?
小白:既然@有这种效果,那打印passed user verification... welcome [%s] to tv page这两句
小刘:嗯!而且我告诉你这玩意叫做装饰器,作用就是把装饰器下面的函数--函数名当参数传给装饰器函数,不过刚才我给你这个方案还一个弊端,你把执行tv()去掉试试看?
小白对得出结果也表示惊奇,连摇头表示不懂。
小刘给了一张图给小白看

小白看到图后,才想到装饰器等同就是执行了login函数
小白:那我们应该怎么处理这种弊端呢?
小刘:那我问问你,python解释器遇定义函数是什么情况?
小白:把函数刷到内存里,不执行
小刘:好!那我们就利用这一点,给那个装饰器函数里在嵌套一个函数!
小白好像有些恍然大悟,但还是不知道怎么做
小刘:小白!我给你看这个例子
def login(func):
def inner():
print('passed user verification...')
return func
return inner @login
def tv():
print('welcome [%s] to tv page')
小刘;你执行一下,看达到我们的效果没有?
小白欢喜的回到:我们做到了
小刘:别告诉的太早了,还有问题,你执行一下看看,加个tv()
小白加了tv()执行后惊讶地发现,真正tv的功能根本没有执行,小白一脸疑惑!
小刘:小白!你来看看这张图

小刘:你看,我们应该怎么改进,让其执行原来tv函数呢?
小白看着图想了想,不应该return tv内存地址,应该在那写成tv()执行函数
小刘:就按你说的,试一下。

def login(func): #tv
def inner():
print('passed user verification...')
func()
return inner @login #tv = login(tv)
def tv():
print('welcome [%s] to tv page') tv()
小刘:不错哦!实现了哦!
给装饰器加参数
小刘:业务部门调用函数是不是会给装饰器传参数?那如果要加参数应该加到哪呢?
小白想了想

小刘看着小白画的图,哈哈大笑!悟性高!
def login(func): #tv
def inner(arg1,arg2):
print('passed user verification...')
func(arg1,arg2)
return inner @login #tv = login(tv)
def tv(arg1,arg2):
print('welcome [%s] to [%s] tv page'%(arg1,arg2)) tv('alex','江西卫视')
小刘:小白!是不是有不同的业务用我们的平台,那他们是不是有可能往装饰器里传的参数个数都有可能不同?
小白:嗯嗯!
小刘:那怎么解决这个需求呢?
小白想了又想,支支吾吾的回答了个:难道要用函数里的动态参数??
小刘:没错!那我们来看看怎么改进吧
def login(func): #tv
def inner(*args,**kwargs):
print('passed user verification...')
func(*args,**kwargs)
return inner @login #movie = login(movie)
def movie(arg1):
print('welcome [%s] to movie page'%arg1) @login #tv = login(tv)
def tv(arg1,arg2):
print('welcome [%s] to [%s] tv page'%(arg1,arg2)) tv('alex','江西卫视')
print('*'*25)
movie('eric') 结果为:
passed user verification...
welcome [alex] to [江西卫视] tv page
*************************
passed user verification...
welcome [eric] to movie page
小白:实现了!
小白乐地得都合不上嘴了!
小刘:好了!装饰器大部分内容给你讲完了,最后剩下那点内容就算你回家的任务吧,就是多个装饰器运行流程,以你的领悟能力,应该没问题。
小刘:另外就多个装饰器,我总结了两句话,在执行过程中,你结合这两句话去理解:
1.多个装饰器在调用时,从外向里
2.装饰器的封装是从里向外的
小白:好!没问题!小刘!你辛苦了
小刘:应该的!那回去吧!
欢迎大家对我的博客内容提出质疑和提问!谢谢
笔者:拍省先生
python基础-第五篇-5.3装饰器的更多相关文章
- python基础之迭代器、生成器、装饰器
一.列表生成式 a = [0,1,2,3,4,5,6,7,8,9] b = [] for i in a: b.append(i+1) print(b) a = b print(a) --------- ...
- Python基础4 迭代器,生成器,装饰器,Json和pickle 数据序列化
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- 7th,Python基础4——迭代器、生成器、装饰器、Json&pickle数据序列化、软件目录结构规范
1.列表生成式,迭代器&生成器 要求把列表[0,1,2,3,4,5,6,7,8,9]里面的每个值都加1,如何实现? 匿名函数实现: a = map(lambda x:x+1, a) for i ...
- python 基础学习笔记(8)--装饰器
**装饰器** - [ ] 装饰器和闭包有很大的联系.有时你需要在不改变源代码的情况下修改已经存在的函数.装饰器的运用可以提高效率,减少重复的代码. - [ ] 装饰器的实质是一个函数.它把一个函数作 ...
- python基础之:九步认识装饰器
step1. 先看个代码吧: def f(): ') f=lambda a:a +100 #覆盖上面的函数f print(f) #函数名指函数所在内存中的位置,入带后面括号表示执行函数 print(f ...
- python基础学习之描述符和装饰器
描述符的了解: 描述符协议: python描述符是一个"绑定行为"的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有: __get__, __set__, 和__ ...
- python基础知识---迭代器、生成器、装饰器
一.迭代器 二.生成器 http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html def func(): #定义生成器,和普通函数的区别是 ...
- python基础语法7 闭包函数与装饰器
闭包函数: 1.闭包函数必须在函数内部定义 2.闭包函数可以引用外层函数的名字 闭包函数是 函数嵌套.函数对象.名称空间与作用域 结合体. # 直接传参 def func(x): print(x) f ...
- Python 基础之面向对象之八步理解装饰器
装饰器:在不改变原有代码的情况下,为该原函数扩展新功能特征:返回新函数,替换旧函数语法:@ 语法糖 1.装饰器原型 #例1: def kuozhan(func): def newfunc(): ...
随机推荐
- centOS7 配置DNS上外网
CentOS7 linux下DNS的永久性添加 I.网上很多讲的dns的永久性添加其实都是暂时性添加,重启网卡后就会丢失.代码如下: echo nameserver 8.8.8.8 > /etc ...
- Mysql定时备份数据脚本
项目集群搭建完成,数据库虽有做主从同步,但考虑到数据安全性,为了满足这个需求那么要每天对数据备份处理, 但每天手动进行备份处理太过于被动,而且白天用户访问,会有数据变化以及在备份时会影响服务器正常运行 ...
- scala flatMap reduceLeft foldLeft
object collection_t1 { def flatMap1(): Unit = { val li = List(,,) val res = li.flatMap(x => x mat ...
- [转]使用rosbridge协议实现安卓跟ros的解耦
安卓与ROS通信的现状 因为ROS官方支持的语言绑定只有C++和Python,所以目前安卓想与ROS通信,必须借助半官方的rosjava包,而Rosjava太重了,因为它跟C++/Python一样,是 ...
- 解决Maven项目 Missing artifact jdk.tools:jdk.tools:1.7的错误
因学习项目需要,在pom.xml添加hbase-client依赖的时候提示解决Maven工程中报 Missing artifact jdk.tools:jdk.tools:1.7的提示信息,之前遇到这 ...
- MyBatis-Spring 使用总结
说明:Java-based Config. 不是通过 mybatis 的 SqlSessionFactoryBuilder 来创建 SqlSessionFactory ,而是通过 mybatis-sp ...
- MyBatis是支持普通 SQL查询
MyBatis是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简单的 XML或注解用于配置 ...
- Canvas组件:画布,可以实现动画操作
Canvas组件:画布,可以实现动画操作. TextArea:文本域. 在单行文本域中回车会激发ActionEvent. 用CheckBoxGroup实现单选框功能. Java中,单选框和复选框都是使 ...
- hdu 4928 Series 2 (优化+模拟)
题意: 一个含n个数的序列a,每两个相邻的数相减得到一个新数,这些数组成一个新的序列. 假设全部得到的序列都满足非严格的单调性.则原序列为nice series.假设给出的序列 本来不满足单调性.它是 ...
- 求出每个team粉丝数最多的3个国家
有这么个表 fans(team,nationality,fanCount) 'Barcelona','Germany',12000'Barcelona','Spain',18000'Barcelona ...