装饰器,英文名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