python高级-装饰器(19)
一、什么是闭包
先看一个例子:
- #定义一个函数
- def test(number):
- #在函数内部在定义一个函数,并且这个函数用到外围函数的变量
- #那么将这个函数及用到的一些变量称之为闭包
- def test_in(number_in):
- print("在test_in函数内部,number_in的值为:%d"%number_in)
- return number+number_in
- #其实这里返回的是闭包,也就是内部的函数引用
- return test_in
- #给test函数赋值,这个20就是参数number
- ret = test(20)
- #注意这里的100就是参数number_in
- print(ret(100))
运行结果为:
- 在test_in函数内部,number_in的值为:100
- 120
说明:
- 在函数内部在定义一个函数,并且这个函数用到外围函数的变量,那么将这个函数及用到的一些变量称之为闭包
- 在其他语言里面不允许函数内部在定义函数,但是python中的闭包可以
二、什么是装饰器
装饰器是程序开发中经常会⽤到的⼀个功能,所以这也是Python⾯试中必问的问题。
定义:
- 装饰器本身就是一个函数
- 为其他函数提供附加功能
- 不改变被修饰函数的源代码
- 不改变原调用方式
- 装饰器=高阶函数+嵌套函数
知识点:
- 函数本身就是一个变量(意味着可以被复制给一个变量:test=test(1) )
- 高阶函数:把函数名当成一个实参传递给另一个函数func(test1) (不改变源代码的前提下添加代码)
- 返回值中包含函数名return deco (不改变函数的调用方式)
- 嵌套函数:函数中加入新的函数
典型结构:
- def func(args):
- def func_in(args_in):
- pass
- return func_in
三、装饰器案例
1、先看一个例子
某公司有多个研发部⻔,1个基础平台部⻔,基础平台负责提供底层的功能,如:数据库操作、redis调⽤、监控API等功能。研发部⻔使⽤基础功能时,只需调⽤基础平台提供的功能即可。如下:
- --------------基础平台提供的功能--------------
- def func1():
- pass
- def func2():
- pass
- def func3():
- pass
- --------------研发部门A使用基础平台--------------
- func1()
- func2()
- func3()
- --------------研发部门B使用基础平台--------------
- func1()
- func2()
- func3()
随着项目进度的深入,产品经理提出,要在基础平台的提供的所有功能中,添加验证功能,不能谁都可以使用基础平台的全部功能,即执行功能前,先进行验证。
项目经理将此功能交给了小A去实现。
小A就去和每个研发部沟通,让每个研发部自己把验证的代码加上,结果第二天就被辞职了。
项目经理又将此功能交给了小B去实现。
小B吸取小A的经验,开始自己改代码:
- --------------基础平台提供的功能--------------
- def func1():
- #验证1
- #验证2
- pass
- def func2():
- #验证1
- #验证2
- pass
- def func3():
- #验证1
- #验证2
- pass
- --------------研发部门A使用基础平台--------------
- func1()
- func2()
- func3()
- --------------研发部门B使用基础平台--------------
- func1()
- func2()
- func3()
没过多久小B也被开除了。。。
项目经理又把工作交给了小C,小C对基础平台代码进行重构,其他业务部门无需做任何修改
- --------------基础平台提供的功能--------------
- def check_login():
- #验证1
- #验证2
- pass
- def func1():
- check_login()
- pass
- def func2():
- check_login()
- pass
- def func3():
- check_login()
- pass
- --------------研发部门A使用基础平台--------------
- func1()
- func2()
- func3()
- --------------研发部门B使用基础平台--------------
- func1()
- func2()
- func3()
项目经理看后表示还不错,但是感觉还是差了一点点,于是决定不再低调,再也不让小弟做了,于是自己做了一个方案:
- --------------基础平台提供的功能--------------
- def check_login(func):
- def inner():
- #验证1
- #验证2
- func()
- return inner
- @check_login
- def func1():
- pass
- @check_login
- def func2():
- pass
- @check_login
- def func3():
- pass
- --------------研发部门A使用基础平台--------------
- func1()
- func2()
- func3()
- --------------研发部门B使用基础平台--------------
- func1()
- func2()
- func3()
对于上述代码,也是仅仅对基础平台的代码进⾏修改,就可以实现在其他⼈调⽤函数 func1(), func2(), func3()之前都进⾏【验证】操作,并且其他研发部⻔⽆需做任何操作。
单独以func1()为例讲解:
- def check_login(func):
- def inner():
- #验证1
- #验证2
- func()
- return inner
- @check_login
- def func1():
- pass
python解释器就会从上到下解释代码,步骤如下:
- def check_login(func): ==>将check_login函数加载到内存
- @check_login
没错, 从表⾯上看解释器仅仅会解释这两句代码,因为函数在没有被调⽤之前其内部代码不会被执⾏。从表⾯上看解释器着实会执⾏这两句,但是 @check_login这⼀句代码⾥却有⼤⽂章, @函数名 是python的⼀种语法糖
上例@check_login内部会执⾏⼀下操作:
执行check_login函数,并将@check_login下面的函数作为check_login函数的参数,
即@check_login等价于check_login(func1),所以内部就会去执行:
- def check_login(func):
- def inner():
- #验证1
- #验证2
- func() #func是参数。此时的func就是函数func1()
- #返回inner,inner的内部就是执行func1()函数,但是执行func1()函数前,进行了验证1,验证2
- return inner
check_login() 的返回值
将执行完的chenk_login函数返回值赋值 给@check_login下面的函数的函数名func1 即将check_login()的返回值再重新赋值给func1,即:
- 新func1 = def inner():
- #验证1
- #验证2
- func() #func是参数。此时的func就是函数func1()
- #返回inner,inner的内部就是执行func1()函数,但是执行func1()函数前,进行了验证1,验证2
- return inner
所以,以后研发部门想要执行func1函数时,就会执行新func1函数,在新func1函数内部先执行验证,再执行原来的func1函数,然后将原来func1函数的返回值返回给了业务调用者。
四、装饰器应用
- #定义一个装饰器:实现加粗效果
- def makeBold(fn):
- def wrapped():
- return "<b>"+fn()+"</b>"
- return wrapped
- #定义一个装饰器:实现斜体效果
- def makeItalic(fn):
- def wrapped():
- return "<i>"+fn()+"</i>"
- return wrapped
- #使用装饰器装饰函数
- @makeBold
- def test():
- return "Hello World"
- #使用装饰器装饰函数
- @makeItalic
- def test1():
- return "Hello World"
- @makeBold
- @makeItalic
- def test2():
- return "Hello World"
- print(test())
- print(test1())
- print(test2())
运行结果为:
- <b>Hello World</b>
- <i>Hello World</i>
- <b><i>Hello World</i></b>
五. 装饰器示例
例1:⽆参数的函数
- def test_out(func):
- def test_in():
- print("name-%s"%func.__name__)
- func()
- return test_in
- @test_out
- def test():
- pass
- test()
运行结果为:name-test
例2:被装饰的函数有参数
- def test_out(func):
- def test_in(a,b):
- print(a,b)
- func(a,b)
- return test_in
- @test_out
- def test(a,b):
- print("a+b=",a+b)
- test(1,2)
运行结果为:
- 1 2
- a+b= 3
例3:被装饰的函数有不定⻓参数
- def test_out(func):
- def test_in(*args,**kwargs):
- func(*args,**kwargs)
- return test_in
- @test_out
- def test(*args,**kwargs):
- print(args,kwargs)
- test(1)
- test(1,2)
- test(1,2,3,k="v")
运行结果为:
- (1,) {}
- (1, 2) {}
- (1, 2, 3) {'k': 'v'}
说明:如果被修饰的函数有参数,则装饰器内部的函数也要有同样个数的参数才可以匹配成功。
例4:装饰器中的return
- def test_out(func):
- def test_in():
- func()
- return test_in
- @test_out
- def test():
- return "hello"
- result = test()
- print(result)
运行结果为:None
如果修改装饰器为 return func() ,则运⾏结果:
- def test_out(func):
- def test_in():
- return func()
- return test_in
- @test_out
- def test():
- return "hello"
- result = test()
- print(result)
运行结果为:hello
⼀般情况下为了让装饰器更通⽤,可以有return
例5:装饰器带参数,在原有装饰器的基础上,设置外部变量
六、类装饰器
装饰器函数其实是⼀个接⼝约束,它必须接受⼀个callable对象作为参数,然后返回⼀个callable对象。在Python中⼀般callable对象都是函数,但也有例外。只要某个对象重写了 __call__() ⽅法,那么这个对象就是callable
- class Test():
- def __call__(self):
- print("call me")
- t = Test()
- t()
执行结果:call me
类装饰器demo
- class Test():
- def __init__(self,func):
- print("----初始化----")
- print("func name is %s"%func.__name__)
- self.__func = func
- def __call__(self):
- print("----类装饰器的功能----")
- self.__func()
- print("----类装饰器执行完毕----")
- @Test
- def test():
- print("----test----")
- test()
运行结果为:
- ----初始化----
- func name is test
- ----类装饰器的功能----
- ----test----
- ----类装饰器执行完毕----
说明:
- 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
- 并且会把test这个函数名当做参数传递到__init__方法中,即在__init__方法中的func变量执行了test函数体
- test函数相当于指向了用Test创建出来的实例对象
- 挡在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
- 为了能够在__call__方法中调用原来的test指向的函数体,所以在__init__方法中就需要一个实例属性保存这个引用,所以才有了self.__func = func这句代码,从而在调用__call__方法中就能调用test
python高级-装饰器(19)的更多相关文章
- Python函数装饰器高级用法
在了解了Python函数装饰器基础知识和闭包之后,开始正式学习函数装饰器. 典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过 ...
- 【转】详解Python的装饰器
原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...
- 详解Python的装饰器
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...
- Python的装饰器实例用法小结
这篇文章主要介绍了Python装饰器用法,结合实例形式总结分析了Python常用装饰器的概念.功能.使用方法及相关注意事项 一.装饰器是什么 python的装饰器本质上是一个Python函数,它可以让 ...
- 进阶Python:装饰器 全面详解
进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用 ...
- 我终于弄懂了Python的装饰器(二)
此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 二 ...
- 我终于弄懂了Python的装饰器(四)
此系列文档: 1. 我终于弄懂了Python的装饰器(一) 2. 我终于弄懂了Python的装饰器(二) 3. 我终于弄懂了Python的装饰器(三) 4. 我终于弄懂了Python的装饰器(四) 四 ...
- Python各式装饰器
Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...
- Python札记 -- 装饰器补充
本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...
随机推荐
- Flink on yarn的配置及执行
1. 写在前面 Flink被誉为第四代大数据计算引擎组件,即可以用作基于离线分布式计算,也可以应用于实时计算.Flink可以自己搭建集群模式已提供为庞大数据的计算.但在实际应用中.都是计算hdfs上的 ...
- 关于spring的自动注入
关于spring的自动注入 spring里面可以设置BeanDefinition自动注入类型,默认为AUTOWIRE_NO(不进行自动注入).mybatis里面的扫描接口生成MapperFactory ...
- python_web框架
一.web框架 web框架: 自己完成socket的web框架:如,Tornado等 由WSGI完成socket的web框架:如,Django.flash等 两种实现过程: 第二种WSGI方式的,由于 ...
- spark ML pipeline 学习
一.pipeline 一个典型的机器学习过程从数据收集开始,要经历多个步骤,才能得到需要的输出.这非常类似于流水线式工作,即通常会包含源数据ETL(抽取.转化.加载),数据预处理,指标提取,模型训练与 ...
- Git帮助之初始化项目设置向导
初始化项目设置向导 Git设置: git config --global user.name "Your Name Here" # 设置Git提交时的默认用户名,推荐使用本站用户名 ...
- 数据导出Excel表格
public String exportInfoFr(String path,String name,String startdate,String enddate,SysUser user){ Li ...
- DAY1 VS2017&CUDA10.01环境搭建
Visual Studio工程配置情况: VC++目录配置: C:\ProgramData\NVIDIA Corporation\CUDA Samples\v10.\common\lib\x64 C: ...
- C++ 初读vector
vector 向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container).跟任意其它类型容器一样,它能够存放各种类型的对象. Character 高效 C++标准要 ...
- 《Java项目中classpath路径详解》
项目里用到了classpath路径来引用文件,那么classpath指的是哪里呢 我首先把上面的applicationContext.xml文件放在了src目录下发现可以. 那么classpath到底 ...
- C#的排序Sort和OrderBy扩展方法
可以实现一个IComparable接口的CompareTo方法,或者是给予List的Sort扩展方法,传入委托实现,举个例子: list.Sort((a, b) => { var o = a.s ...