小白发呆的看着窗外,同事们陆陆续续的地来到公司,想起算法,小白就飘飘然了。突然后面传来一声呼唤,原来是小刘!

  小刘:不好意思啊!堵车了,就来晚了点,不耽误你的时间,咱们就开启的今天的培训内容吧!

  小白连忙说:没事,可以开始啦!

函数内存与执行函数

  小刘:那我给你看一段代码,你看看会得到什么结果

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装饰器的更多相关文章

  1. 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) --------- ...

  2. Python基础4 迭代器,生成器,装饰器,Json和pickle 数据序列化

    本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...

  3. 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 ...

  4. python 基础学习笔记(8)--装饰器

    **装饰器** - [ ] 装饰器和闭包有很大的联系.有时你需要在不改变源代码的情况下修改已经存在的函数.装饰器的运用可以提高效率,减少重复的代码. - [ ] 装饰器的实质是一个函数.它把一个函数作 ...

  5. python基础之:九步认识装饰器

    step1. 先看个代码吧: def f(): ') f=lambda a:a +100 #覆盖上面的函数f print(f) #函数名指函数所在内存中的位置,入带后面括号表示执行函数 print(f ...

  6. python基础学习之描述符和装饰器

    描述符的了解: 描述符协议: python描述符是一个"绑定行为"的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有: __get__, __set__, 和__ ...

  7. python基础知识---迭代器、生成器、装饰器

    一.迭代器 二.生成器 http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html def func(): #定义生成器,和普通函数的区别是 ...

  8. python基础语法7 闭包函数与装饰器

    闭包函数: 1.闭包函数必须在函数内部定义 2.闭包函数可以引用外层函数的名字 闭包函数是 函数嵌套.函数对象.名称空间与作用域 结合体. # 直接传参 def func(x): print(x) f ...

  9. Python 基础之面向对象之八步理解装饰器

    装饰器:在不改变原有代码的情况下,为该原函数扩展新功能特征:返回新函数,替换旧函数语法:@ 语法糖 1.装饰器原型 #例1: def kuozhan(func):    def newfunc():  ...

随机推荐

  1. angular初体验

    所有需要ng管理的代码必须被包裹在一个有ng-app指令的元素中ng-app是ng的入口,表示当前元素的所有指令都会被angular管理(对每一个指令进行分析和操作) 利用angular实现双向绑定: ...

  2. 关闭IOS更新功能(ios4/5/6)

    防止IOS升级: 工具:ifunbox 展开/System/Library/LaunchDaemons,将下面4个文件删除(不推荐)或者改名(后缀也得改),改名后记得必须重启. com.apple.m ...

  3. Hive入门笔记---1.Hive简单介绍

    1. Hive是什么 Hive是基于Hadoop的数据仓库解决方案.由于Hadoop本身在数据存储和计算方面有很好的可扩展性和高容错性,因此使用Hive构建的数据仓库也秉承了这些特性.这是来自官方的解 ...

  4. java常用操作

    1.properties文件中文转换 在cmd中进入到文件所在目录执行(其他操作请见命令帮助):native2ascii -reverse  messages_zh_CN.properties b.t ...

  5. am335x -- kio 控制接口

    //example #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include < ...

  6. C++ 类中的静态成员变量,静态成员函数

    //类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...

  7. JS关于浏览器尺寸的方法

    document.body.clientWidth BODY对象宽度.通配符未清零margin的时候,小于页面可见区域宽度document.body.clientHeight BODY对象高度.doc ...

  8. windows2003 iis6.0站点打不开,找不到服务器或 DNS 错误【转】

    最近服务器经常出现打不开网站的现象,有时出现在上午,有时出现在中午,几乎天天都会出现一次,出现问题时,无论是回收程序池还是重启IIS或者关闭其它一些可能有影响的服务,都不能解决问题.网站打不开时,有如 ...

  9. java深度搜索与广度优先搜索

    图结构展示: 实现过程: 首先,我们来看看图结构在代码中的实现.有三块逻辑: 1.图中的节点: public class GraphNode { public List<GraphEdge> ...

  10. ThinkPHP项目笔记之RBAC(权限)中篇

    现在,说说添加权限,权限管理列表 c.添加权限