先看一个例子:python
#定义一个函数
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))
运行结果为:redis
在test_in函数内部,number_in的值为:100
120
说明:数据库
装饰器是程序开发中常常会⽤到的⼀个功能,因此这也是Python⾯试中必问的问题。闭包
定义:app
知识点:函数
典型结构:spa
def func(args): def func_in(args_in): pass
return func_in
一、先看一个例子code
某公司有多个研发部⻔,1个基础平台部⻔,基础平台负责提供底层的功能,如:数据库操做、redis调⽤、监控API等功能。研发部⻔使⽤基础功能时,只需调⽤基础平台提供的功能便可。以下:对象
--------------基础平台提供的功能--------------
def func1(): pass
def func2(): pass
def func3(): pass
--------------研发部门A使用基础平台-------------- func1() func2() func3() --------------研发部门B使用基础平台-------------- func1() func2() func3()
随着项目进度的深刻,产品经理提出,要在基础平台的提供的全部功能中,添加验证功能,不能谁均可以使用基础平台的所有功能,即执行功能前,先进行验证。blog
项目经理将此功能交给了小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解释器就会从上到下解释代码,步骤以下:
1 def check_login(func): ==>将check_login函数加载到内存 2 @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----
----类装饰器执行完毕----
说明: