注意事项
- 何时执行装饰器
函数装饰器在导入模块
时立即执行,而被装饰的函数只在明确调用时运行。这突出了 Python 程序员所说的导入时和运 行时之间的区别。
Python何时执行装饰器 - 顽强的allin - 博客园 - 装饰器是可以叠加使用的,那么使用装饰器以后代码是什么顺序呢
对于Python
中的@
语法糖,装饰器的调用顺序与使用@
语法糖声明的顺序相反。
比如
@decorator1
@decorator2
def f(a,b):
pass
执行顺序是
f(3, 4) = decorator1(decorator2(f(3, 4)))
-
@decorator
这个语法相当于 执行func = decorator(func)
,为func
函数装饰并返回
装饰函数
(1)被装饰器的函数带有形参
# -*- coding:utf-8 -*-
from enum import Enum, unique
import time
def print_run_time(fun):
def wrapper(*args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
start_time = time.time()
fun(*args, **kwargs)
run_time = time.time() - start_time
print('run_time is:', run_time)
return wrapper
@print_run_time
def test_fun(min_value, max_value):
sum = 0
for i in range(min_value, max_value, 1):
sum += i
print('sum is:', sum)
wrapper(*args, **kwargs)
用来处理被装饰的函数带有各种形参的情况。
- 当调用
if __name__ == '__main__':
test_fun(1, 1000000)
输出
('args:', (1, 1000000))
('kwargs:', {})
('sum is:', 499999500000L)
('run_time is:', 0.07899999618530273)
当调用
if __name__ == '__main__':
test_fun(min_value=1, max_value=1000000)
输出
('args:', ())
('kwargs:', {'max_value': 1000000, 'min_value': 1})
('sum is:', 499999500000L)
('run_time is:', 0.08299994468688965)
(2)被装饰器的函数带有返回值
def print_run_time(fun):
def wrapper(*args, **kwargs):
print('args:', args)
print('kwargs:', kwargs)
start_time = time.time()
result = fun(*args, **kwargs)
run_time = time.time() - start_time
print('run_time is:', run_time)
return result
return wrapper
@print_run_time
def test_fun(min_value, max_value):
sum = 0
for i in range(min_value, max_value, 1):
sum += i
print('sum is:', sum)
return sum
if __name__ == '__main__':
result = test_fun(min_value=1, max_value=1000000)
print('result:', result)
(3)装饰器带有形参
带有参数的装饰器需要再增加一层封装
def print_run_time(debug_flag):
def fun_wrapper(fun):
def wrapper(*args, **kwargs):
start_time = time.time()
result = fun(*args, **kwargs)
run_time = time.time() - start_time
if debug_flag:
print('args:', args)
print('kwargs:', kwargs)
print('run_time is:', run_time)
return result
return wrapper
return fun_wrapper
DEBUG_FLAG = True
@print_run_time(DEBUG_FLAG)
def test_fun(min_value, max_value):
sum = 0
for i in range(min_value, max_value, 1):
sum += i
print('sum is:', sum)
return sum
例子中想要给装饰器添加参数,需要再增加一层封装。比如这里做一个输出开关。当DEBUG_FLAG = True
才输出信息。
(4)@wraps(func)
的作用
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python
的functools
包中提供了一个叫wraps
的decorator
来消除这样的副作用。写一个decorator
的时候,最好在实现之前加上functools
的wrap
,它能保留原有函数的名称。
- 不加
wrap
if __name__ == '__main__':
result = test_fun(min_value=1, max_value=1000000)
print('fun_name', test_fun.__name__)
输出
('fun_name', 'wrapper')
- 添加
wrap
from functools import wraps
def print_run_time(debug_flag):
def fun_wrapper(fun):
@wraps(fun)
def wrapper(*args, **kwargs):
start_time = time.time()
result = fun(*args, **kwargs)
run_time = time.time() - start_time
if debug_flag:
print('args:', args)
print('kwargs:', kwargs)
print('run_time is:', run_time)
return result
return wrapper
return fun_wrapper
输出结果:
('fun_name', 'test_fun')
装饰类,或者装饰类中的方法
# -*- coding:utf-8 -*-
from enum import Enum, unique
import time
from functools import wraps
SKILL_MAP = {}
DEBUG_FLAG = True
def register_skill(skill_type):
def wrapper(cls):
global SKILL_MAP
assert cls.skill_cd > 0, 'skill_cd: %s should > 0' % (cls.skill_cd,)
SKILL_MAP[skill_type] = cls
return cls
return wrapper
def print_run_time(debug_flag):
def fun_wrapper(fun):
@wraps(fun)
def wrapper(*args, **kwargs):
start_time = time.time()
result = fun(*args, **kwargs)
run_time = time.time() - start_time
if debug_flag:
print('args:', args)
print('kwargs:', kwargs)
print('run_time is:', run_time)
return result
return wrapper
return fun_wrapper
@unique
class SkillType(Enum):
BUFF = 1
FLY = 2
class BaseSkill(object):
skill_cd = 0
@print_run_time(DEBUG_FLAG)
def create_skill(self):
pass
def destroy_skill(self):
pass
@register_skill(SkillType.BUFF)
class BuffSkill(BaseSkill):
skill_cd = 1.0
def create_skill(self):
super(BuffSkill, self).create_skill()
print('create buff skill')
def destroy_skill(self):
print('destroy buff skill')
@register_skill(SkillType.FLY)
class FlySkill(BaseSkill):
skill_cd = 2.0
def create_skill(self):
super(FlySkill, self).create_skill()
print('create fly skill')
def destroy_skill(self):
super(FlySkill, self).destroy_skill()
print('destroy fly skill')
def skill_facory(skill_type):
skill_class = SKILL_MAP[skill_type]
skill = skill_class()
return skill
if __name__ == '__main__':
skill = skill_facory(SkillType.FLY)
skill.create_skill()
skill.destroy_skill()
网友评论