Decorators(装饰器)初级
Decorators(装饰器)初级.Decorators提供了一种简单的句法来实现运行更高级的函数(higher-orderfunctions).根据定义,decorator是一种函数,它可以应用其他函数并拓展其行为而不用对函数进行明确地修改。听起来有些令人困惑,但是事实上它并不复杂,特别是当我们研究完下面几个例子后。
在这个介绍性教程中,我们会看到什么是decorators和如何去创建并应用它。
首先,最重要的是在你能够理解decorators之前,你必须先理解...函数是如何工作的.最基本且最重要的,函数会根据传入的数据返回一个值。
deffoo(bar):
returnbar+1
printfoo(2)==3
第一类对象(FirstClassObjects)
在python中,函数是第一类对象(first-classobjects)。这意味着函数可以被传递,像参数一样被使用,就像其他的类型(例如:string,int,float)一样。
deffoo(bar):
returnbar+1
printfoo
printfoo(2)
printtype(foo)
defcall_foo_with_arg(foo,arg):
returnfoo(arg)
printcall_foo_with_arg(foo,3)
内嵌函数(NestedFunctions)
由于在Python里函数优先的性质,你可以在其他函数里定义一个新函数。这类的函数被称作内嵌函数。
defparent():
print"Printingfromtheparent()function."
deffirst_child():
return"Printingfromthefirst_child()function."
defsecond_child():
return"Printingfromthesecond_child()function."
printfirst_child()
printsecond_child()
当你调用parent()的时候会发生什么呢?请先想一会儿。你应该会得到……
Printingfromtheparent()function.
Printingfromthefirst_child()function.
Printingfromthesecond_child()function
尝试去调用first_child()一下。你应该会得到一个错误:
Traceback(mostrecentcalllast):
File"decorator3.py",line15,in<module>
first_child()
NameError:name'first_child'isnotdefined
我们了解到了什么?
不论你什么时候调用parent(),子函数first_child()和second_child()也都被调用,并且,因为作用域的缘故,这两个子函数在母函数之外都是不可用的(例如不可以被调用)。
返回函数(ReturningFunctions)
Python也允许你在函数中返回其他函数的函数值。让我们改变一下之前的函数作为这个的例子。
defparent(num):
deffirst_child():
return"Printingfromthefirst_child()function."
defsecond_child():
return"Printingfromthesecond_child()function."
try:
assertnum==10
returnfirst_child
exceptAssertionError:
returnsecond_child
foo=parent(10)
bar=parent(11)
printfoo
printbar
printfoo()
printbar()
前两个输出的结果是:
<functionfirst_childat0x1004a8c08>
<functionsecond_childat0x1004a8cf8>
这简单地说明了foo对应着first_child()函数,bar对应着second_child()函数。
后两个函数结果的输出证明了这一点。
Printingfromthefirst_child()function.
Printingfromthesecond_child()function.
最后,你有没有注意到在第三个例子中,我们在母函数中执行了子函数,例如:second_child()。同时,在最后一个例子中,当我们调用子函数first_child时,我们没有在其中添加插入成分,以便我们在将来可以调用它。清楚了吗?
现在,我的朋友,你已经做好准备来学习decorators了!
让我们来看两个例子…
第一个例子:
defmy_decorator(some_function):
defwrapper():
print"Somethingishappeningbeforesome_function()iscalled."
some_function()
print"Somethingishappeningaftersome_function()iscalled."
returnwrapper
defjust_some_function():
print"Wheee!"
just_some_function=my_decorator(just_some_function)
just_some_function()
你能猜一下输出结果会是什么吗?试一试。
Somethingishappeningbeforesome_function()iscalled.
Wheee!
Somethingishappeningaftersome_function()iscalled.
想要理解这里发生了什么,你只需要回去看看前四个例子。我们差不多只运用了所有已经学过了的东西。简单地说,decorators包装了一个函数,然后修改了它的行为(功能)。
让我们再进一步,增加一个if语句。
第二个例子:
defmy_decorator(some_function):
defwrapper():
num=10
ifnum==10:
print"Yes!"
else:
print"No!"
some_function()
print"Somethingishappeningaftersome_function()iscalled."
returnwrapper
defjust_some_function():
print"Wheee!"
just_some_function=my_decorator(just_some_function)
just_some_function()
这将输出:
Yes!
Wheee!
Somethingishappeningaftersome_function()iscalled.
是时候来一点语法糖(syntacticsugar)了!
Python允许你运用@标志来简化decorators的调用(这叫做“pie”句法)
让我们为我们的decorator创建一个模块:
fromdecorator7importmy_decorator
@my_decorator
defjust_some_function():
print"Wheee!"
just_some_function()
当你运行这个例子时,你应该会得到与之前的相同的输出结果:
Yes!
Wheee!
Somethingishappeningaftersome_function()iscalled.
所以,@my_decorator只是just_some_function=my_decorator(just_some_function).的一个更简单的表示方式。
现实世界
来看些关于现实生活的例子……
importtime
deftiming_function(some_function):
"""
Outputsthetimeafunctiontakes
toexecute.
"""
defwrapper():
t1=time.time()
some_function()
t2=time.time()
return"Timeittooktorunthefunction:"+str((t2-t1))+"\n"
returnwrapper
@timing_function
defmy_function():
num_list=[]
forxin(range(0,10000)):
num_list.append(x)
print"\nSumofallthenumbers:"+str((sum(num_list)))
printmy_function()
这个程序在你运行my_function()会返回刚开始运行的时间点和运行后的时间点。之后,我们只要简单的减去这两个数便可以知道这个函数到运行了多久。
运行一下程序。一行一行的输入,完成它。确保你知道这个程序如何工作。
fromtimeimportsleep
defsleep_decorator(function):
"""
Limitshowfastthefunctionis
called.
"""
defwrapper(*args,**kwargs):
sleep(2)
returnfunction(*args,**kwargs)
returnwrapper
@sleep_decorator
defprint_number(num):
returnnum
printprint_number(222)
forxinrange(1,6):
printprint_number(x)
这个decorator是用来限定速率的。请自己测试一下。
最后,一个在Python里最常被用到的decorators是login_required()。它可以用来确保一名使用者在他/她进入一个特殊通道之前可以登录或者进行正确的身份验证。(如这个例子里的/secret)
fromfunctoolsimportwraps
fromflaskimportg,request,redirect,url_for
deflogin_required(f):
@wraps(f)
defdecorated_function(*args,**kwargs):
ifg.userisNone:
returnredirect(url_for('login',next=request.url))
returnf(*args,**kwargs)
returndecorated_function
@app.route('/secret')
@login_required
defsecret():
Pass
你注意到函数被传递给decorator:functools.wraps()了么。这简单地保存了(preserves)封装函数的元数据。
Python培训、Python培训班、Python培训机构,就选光环大数据!
还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!
大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服!