装饰器,英文名Decorator,有一个“@”符号。如果学过Java,就知道它和注解(Annotation)类似。
Python的实现是通过语法糖,本文旨在解开语法糖,用代码回答问题。
先来看一个装饰器的例子:
def deco(func):
print("before deco.")
func()
print("after deco.")
return func
@deco
def myfunc():
print("myfunc called.")
myfunc()
myfunc()
那么执行结果是:
before deco.
myfunc called.
after deco.
myfunc called.
myfunc called.
先不要问为什么?再来看下面的例子:
def deco(func):
print("before deco.")
func()
print("after deco.")
return func
def myfunc():
print("myfunc called.")
myfunc = deco(myfunc)
myfunc()
myfunc()
执行结果是:
before deco.
myfunc called.
after deco.
myfunc called.
myfunc called.
有没有看到,执行结果是一样的,就是这样,@deco的作用相当于是 myfunc = deco(myfunc) 这一句赋值语句,为什么说它是语法糖,就是这样啊!
在Python这里一切都是那样自然而然,你可以用原生的代码来解释装饰器。
上面的例子只是做介绍用,目的是通过不使用装饰器的代码来说明。
下面举一个常用的例子,记录一个函数运行的时间:
import time
import platform
def time_cost(func):
def _time_cost():
if platform.system() == 'Windows':
beg = time.clock()
func()
print('cost:', (time.clock() - beg))
else:
beg = time.time()
func(num)
print('cost:', (time.time() - beg))
return _time_cost
@time_cost
def calc_sleep():
for item in range(3):
time.sleep(1)
print('calc_sleep()')
calc_sleep()
执行结果:
calc_sleep()
cost: 3.00739021746
可以想到如果不用装饰器那么就是这样的:
import time
import platform
def time_cost(func):
def _time_cost():
if platform.system() == 'Windows':
beg = time.clock()
func()
print('cost:', (time.clock() - beg))
else:
beg = time.time()
func(num)
print('cost:', (time.time() - beg))
return _time_cost
def calc_sleep():
for item in range(3):
time.sleep(1)
print('calc_sleep()')
calc_sleep = time_cost(calc_sleep)
calc_sleep()
执行结果:
calc_sleep()
cost: 3.00060552257
那么有的时候又想记录花费时间,又想取得执行所在目录怎么办?
import time
import platform
import os
def time_cost(func):
def _time_cost():
if platform.system() == 'Windows':
beg = time.clock()
func()
print('cost:', (time.clock() - beg))
else:
beg = time.time()
func(num)
print('cost:', (time.time() - beg))
return _time_cost
def curr_dir(func):
def _curr_dir():
print(os.getcwd())
func()
return _curr_dir
@time_cost
@curr_dir
def calc_sleep():
for item in range(3):
time.sleep(1)
print('calc_sleep()')
calc_sleep()
执行结果:
C:\Program Files (x86)\Notepad++
calc_sleep()
cost: 3.00123433447
那么多个装饰器,不用@符号会是怎么样的呢?
import time
import platform
import os
def time_cost(func):
def _time_cost():
if platform.system() == 'Windows':
beg = time.clock()
func()
print('cost:', (time.clock() - beg))
else:
beg = time.time()
func(num)
print('cost:', (time.time() - beg))
return _time_cost
def curr_dir(func):
def _curr_dir():
print(os.getcwd())
func()
return _curr_dir
def calc_sleep():
for item in range(3):
time.sleep(1)
print('calc_sleep()')
calc_sleep = time_cost(curr_dir(calc_sleep))
calc_sleep()
执行结果:
C:\Program Files (x86)\Notepad++
calc_sleep()
cost: 3.0009753887