装饰器(语法糖)
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
例子1.
给hahaha函数加上一个timmer(计算函数执行时间)的功能。
import time def timmer(func): #函数名可以当做函数的参数 def inner(): start = time.time() func() end = time.time() print(start - end) return inner # 语法糖 @timmer # @把hahaha函数名作为参数传到timmer(),执行了一次, 然后进行了重新赋值 hahaha = timmer(hahaha) --> inner() def hahaha(): time.sleep(0.1) print('aaaa') # time(hahaha) 不能改变这个函数的调用方式 # 也不能修改源代码 # hahaha = timmer(hahaha) timmer(hahaha)函数的执行结果返回 inner函数的内存地址,然后赋值给hahaha # hahaha() 就等同于 inner() hahaha()
装饰器的设计模式:开放封闭原则
开放:对扩展是开放的
封闭:对修改是封闭的
刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办?
import time def timer(func): def inner(*args, **kwargs): start_time = time.time() func(*args, **kwargs) end_time = time.time() print(end_time - start_time) return inner @timer def func1(a): time.sleep(2) print(a) func1('bb')
带参数的装饰器
def outer(flag): def timer(func): def inner(*args, **kwargs): if flag: print('执行函数之前要做的') func(*args, **kwargs) if flag: print('执行函数之后要做的') return inner return timer @outer(True) def func2(mode): print(111, mode) func2('rrr')
多个装饰器装饰同一个函数
有些时候,我们也会用到多个装饰器装饰同一个函数的情况。
单个装饰器:
def first(func):
print('%s() was post to first()' % func.__name__)
def _first(*args, **kwargs):
print('Call the function %s() in _first().' % func.__name__)
return func(*args, **kwargs)
return _first
@first # first(test) test = first(test) --> _first
def test():
return 'hello world!'
test()
输出:
test() was post to first()
Call the function test() in _first().
多重装饰器:
def first(func): print('%s() in first' % func.__name__) def _first(*args, **kwargs): print('Call the function %s() in _first().' % func.__name__) return func(*args, **kwargs) return _first def second(func): print('%s() in second()' % func.__name__) def _second(*args, **kwargs): print('Call the function %s() in _second().' % func.__name__) return func(*args, **kwargs) return _second @first # first(test) test = first(test) --> _first @second # second(test) test = second(test) --> _second def test(): return 'hello world!' test()
输出:
test() was post to second() _second() was post to first() Call the function _second() in _first(). Call the function test() in _second().
实际上它是相当于下面的代码:
>>> def test(): return 'hello world' >>> test=second(test) test() was post to second() >>> test <function _second at 0x000000000316D3C8> >>> test=first(test) _second() was post to first() >>> test <function _first at 0x000000000316D358> >>> test() Call the function _second() in _first(). Call the function test() in _second(). 'hello world' >>>