ITS·黑客

Python学习笔记十-装饰器1

2017-04-20  本文已影响57人  6156fc232124

花了很长时间理解清楚什么是装饰器,是不是我太笨了,果真今天没心情学习....

于是,我找了另外的教程去深刻理解什么是装饰器。

其实,简单说装饰器的作用是:定义了一个函数,运行时动态为函数增加功能,但是不想改变函数代码

是不是还是有些难以理解,那我们就来看一个循序渐进的例子!

装饰器的定义对于我而言,很难一下子就理解,于是来看一个小例子:

def foo():

print 'in foo()'

foo()

这是一个很无聊的函数,但是如果想看看执行这个函数用了多长时间......那么我们可以这样做:

import time

def foo():

start = time.clock()

print 'in foo()'

end = time.clock()

print 'used:', end - start

foo()

上述函数实现了需求。可是如果对另一个叫foo2的函数产生了更浓厚的兴趣,怎么办呢?如果把以上新增加的代码复制到foo2里,那如果还想看更多的函数,难道一直复制??

我们可以考虑重新定义一个函数timeit,将foo的引用传递给他,然后在timeit中调用foo并进行计时,这样,我们就达到了不改动foo定义的目的,而且,想看多少个函数,我们都不用去修改函数定义了!

import time

def foo():

print 'in foo()'

def timeit(func):

start = time.clock()

func()

end =time.clock()

print 'used:', end - start

timeit(foo)

这时候问题来了,我们似乎修改了调用部分的代码。原本我们是这样调用的:foo(),修改以后变成了:timeit(foo)。这样的话,如果foo在N处都被调用了,你就不得不去修改这N处的代码。

既然如此,我们就来想想办法不修改调用的代码;如果不修改调用代码,也就意味着调用foo()需要产生调用timeit(foo)的效果。我们可以想到将timeit赋值给foo,但是timeit似乎带有一个参数……想办法把参数统一吧!如果timeit(foo)不是直接产生调用效果,而是返回一个与foo参数列表一致的函数的话……就很好办了,将timeit(foo)的返回值赋值给foo,然后,调用foo()的代码完全不用修改!

#-*- coding: UTF-8 -*-

import time

def foo():

print 'in foo()'

# 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法

def timeit(func):

# 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装

def wrapper():

start = time.clock()

func()

end =time.clock()

print 'used:', end - start

# 将包装后的函数返回

return wrapper

foo = timeit(foo)

foo()

这样,一个简易的计时器就做好了!我们只需要在定义foo以后调用foo之前,加上foo = timeit(foo),就可以达到计时的目的,这也就是装饰器的概念,看起来像是foo被timeit装饰了。

上面这段代码看起来似乎已经不能再精简了,Python于是提供了一个语法来降低字符输入量。

import time

def timeit(func):

def wrapper():

start = time.clock()

func()

end =time.clock()

print 'used:', end - start

return wrapper

@timeit

def foo():

print 'in foo()'

foo()

重点关注@timeit,在定义上加上这一行与另外写foo = timeit(foo)完全等价,千万不要以为@有另外的魔力。除了字符输入少了一些,还有一个额外的好处:这样看上去更有装饰器的感觉。

这样去讲装饰器是不是更加的清晰了,彻底理解!!!

明天发总结的装饰器的各种用法!!!

上一篇 下一篇

猜你喜欢

热点阅读