注意事項
- 何時執(zhí)行裝飾器
函數(shù)裝飾器在導(dǎo)入模塊
時立即執(zhí)行,而被裝飾的函數(shù)只在明確調(diào)用時運行霉囚。這突出了 Python 程序員所說的導(dǎo)入時和運 行時之間的區(qū)別捕仔。
Python何時執(zhí)行裝飾器 - 頑強的allin - 博客園 - 裝飾器是可以疊加使用的,那么使用裝飾器以后代碼是什么順序呢
對于Python
中的@
語法糖,裝飾器的調(diào)用順序與使用@
語法糖聲明的順序相反榜跌。
比如
@decorator1
@decorator2
def f(a,b):
pass
執(zhí)行順序是
f(3, 4) = decorator1(decorator2(f(3, 4)))
-
@decorator
這個語法相當(dāng)于 執(zhí)行func = decorator(func)
闪唆,為func
函數(shù)裝飾并返回
裝飾函數(shù)
(1)被裝飾器的函數(shù)帶有形參
# -*- 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)
用來處理被裝飾的函數(shù)帶有各種形參的情況。
- 當(dāng)調(diào)用
if __name__ == '__main__':
test_fun(1, 1000000)
輸出
('args:', (1, 1000000))
('kwargs:', {})
('sum is:', 499999500000L)
('run_time is:', 0.07899999618530273)
當(dāng)調(diào)用
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)被裝飾器的函數(shù)帶有返回值
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)裝飾器帶有形參
帶有參數(shù)的裝飾器需要再增加一層封裝
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
例子中想要給裝飾器添加參數(shù)钓葫,需要再增加一層封裝悄蕾。比如這里做一個輸出開關(guān)。當(dāng)DEBUG_FLAG = True
才輸出信息础浮。
(4)@wraps(func)
的作用
Python裝飾器(decorator)在實現(xiàn)的時候帆调,被裝飾后的函數(shù)其實已經(jīng)是另外一個函數(shù)了(函數(shù)名等函數(shù)屬性會發(fā)生改變),為了不影響豆同,Python
的functools
包中提供了一個叫wraps
的decorator
來消除這樣的副作用番刊。寫一個decorator
的時候,最好在實現(xiàn)之前加上functools
的wrap
诱告,它能保留原有函數(shù)的名稱撵枢。
- 不加
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
輸出結(jié)果:
('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()