开始前的闲谈:
最近Python越发火热,不管是炒作还是真火,相信每个火爆的事物,背后总有一个不可替代的原因。总的来看,Python之所以火是因为其语法简单,灵活,非常适合初学者,让“从入门到放弃”的时间有所拉长。有人说Python并不能让你独当一面,或者说只掌握Python不能成为一个“能走得更远”的程序员。我认为与其担心、观望、往复纠结,不如踏踏实实先掌握它。老实想想,自己真的“掌握了Python吗?”,我相信真正掌握后,对于继续学习和使用其它语言也是不无帮助的。
言归正传:
接下来分析一点Python之装饰器,希望能够让大家有所参考~
水平有限,有错误大家评论区直接骂!我们的目的是技术成长!
还在呼吸就在学习,让我们一起,在学习的路上一去不返。
先来看一个例子,判断一个数字是否能被3整除:
def is_div_three(num):
return num % 3 == 0
print(is_div_three(6))
运行结果显然是True
接下来,例如我们需要打印1-10000里能被3整除的数,很简单:
def nums_is_div_tree():
for i in range(1, 10000):
if is_div_three(i):
print(i)
nums_is_div_tree()
输出结果是一连串能被3整除的数字。试想我们又有一个需求,想知道这个程序运行的效率,即求运行时间,显然我们可以把上面的函数进行改造:
import time #引入time模块
def time_is_div_tree():
t1 = time.time() #在执行循环前先记录系统时间
for i in range(1, 10000):
if is_div_three(i):
print(i)
t2 = time.time() #在执行循环后再次记录时间
return t2-t1 #两个时间相减获得运行时间
t = time_is_div_tree()
print(t)
执行结果,除了打印出能被3整除的数外,还获得了运行时间:
我们来思考,这种方式求运行时间是否为最佳方案?
试想,我们定义了几十个函数,当我们需要去关注某些函数的运行时间,就要去修改这些函数,加上求时间的代码,有没有一种方式更加简便?装饰器就可以解决这个问题~继续看:
我们定义一个求运行时间的装饰器:
def print_time(func): #装饰器本身是一个函数,参数func是需要执行的函数
def wrapper():
t1 = time.time()
func()
t2 = time.time()
print('running time: {} s'.format(t2-t1))
return wrapper
然后,在上面的nums_is_div_tree()函数上加一行:@print_time:
@print_time
def nums_is_div_tree():
for i in range(1, 10000):
if is_div_three(i):
print(i)
nums_is_div_tree()
看下效果:除了输出了1-10000里能被3整除的数,还打印出了运行时间:
这样,我们需要求哪个函数的运行时间,只要在函数前加上一行@print_time装饰器即可,有没有很方便!
至此,装饰器我们了解了一半。有人会问,如果求n以内能被3整除的数呢?显然我们需要传入一个参数,那么我们修改以上函数:
@print_time
def nums_is_div_tree(maxnum): #使用传入maxnum
for i in range(1, maxnum):
if is_div_three(i):
print(i)
nums_is_div_tree(10000)
运行报错:
原因是wrapper不能传入参数,我们需要修改上述ptint_time装饰器,在wrapper函数中传入参数:
def print_time(func): #装饰器本身是一个函数,参数func是需要执行的函数
def wrapper(arg): #在wrapper中传入参数arg
t1 = time.time()
func(arg) #将arg传入需要执行的函数
t2 = time.time()
print('running time: {} s'.format(t2-t1))
return wrapper
运行一切正常~
又有人提出需求,如果装饰器本身也带有参数呢?比如,求运行时间时,我们需要打印出一段文字:“装饰器print_time正在执行中”
我们再去修改装饰器:
def print_time(text): #这里传入参数
def decorator(func): #嵌套decorator函数来接收需要执行的函数func
def wrapper(arg): #在wrapper中传入参数arg
t1 = time.time()
func(arg) #将arg传入需要执行的函数
t2 = time.time()
print(text)
print('running time: {} s'.format(t2-t1))
return wrapper
return decorator
继续执行:
@print_time('装饰器print_time正在执行中') #传入我们需要打印的内容
def nums_is_div_tree(maxnum):
for i in range(1, maxnum):
if is_div_three(i):
print(i)
nums_is_div_tree(10000)
运行结果,拿到了我们想要的结果:
至此,Python装饰器讨论结束,有没有感觉豁然开朗呢。