什么是装饰器?
通常的用法,装饰器就是用来装饰函数的
我们在什么情况下会使用到装饰器?
普遍情况下是,我们需要用到一个函数,但是这个函数被其他地方调用,且这个函数的功能无法满足此需求,这样我们就可以通过装饰器来使得函数满足现在的需求,且不影响其他地方。
可以说是拓展函数的功能
一、装饰器入门
# 这是装饰函数
def timer(func):
def wrapper(*args, **kw):
t1 = time.time()
# 这是函数真正执行的地方
func(*args, **kw)
t2 = time.time()
# 计算下时长
cost_time = t2-t1
print("花费时间:{}秒".format(cost_time))
return wrapper
# 入门用法:时间计时器#
@timer
def want_sleep(sleep_time):
time.sleep(sleep_time)
want_sleep(1)
返回:
二、带参数的装饰器
# 进阶用法:带参数的函数装饰器#
def say_hello(contry):
def wrapper(func):
def deco(*args, **kwargs):
if contry == "china":
print("你好!")
elif contry == "america":
print('hello.')
else:
return
# 真正执行函数的地方
func(*args, **kwargs)
return deco
return wrapper
@say_hello("china")
def american():
print("我来自中国。")
@say_hello("america")
def chinese():
print("I am from America.")
american()
print("------------")
chinese()
返回:
三、不带参数的类装饰器
class Logger(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[INFO]: the function {func}() is running...".format(func=self.func.__name__))
print("[INFO]: the function {}() is running...".format(self.func.__name__))
return self.func(*args, **kwargs)
@Logger
def say(something):
print("say {}!".format(something))
say("hello")
返回:
以上还展示了format加函数的两种方式,展现效果都一样
tip:
def call(self, *args, **kwargs)的用法
只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。 换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。我们可以 实例对象()
总的来说,当一个类型实现了特殊方法__call__,该类的实例就变成了可调用的类型, 对象名() 等价于 对象名.call() ,有时候可以简化对象的调用,让对象变成可调用的对象, 实现__call__即可.
四、使用偏函数与类实现装饰器
import functools
import time
class DelayFunc:
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Wait for {self.duration} seconds...')
time.sleep(self.duration)
return self.func(*args, **kwargs)
def eager_call(self, *args, **kwargs):
print('Call without delay')
return self.func(*args, **kwargs)
def delay(duration):
# 装饰器:推迟某个函数的执行。
# 同时提供 .eager_call 方法立即执行
# 此处为了避免定义额外函数,
# 直接使用 functools.partial 帮助构造 DelayFunc 实例
return functools.partial(DelayFunc, duration)
@delay(duration=0)
def add(a, b):
print(a+b)
return a+b
add(3, 5)
返回:
对于不了解偏函数的,可以搜索了解一下
五、装饰类的装饰器
instances = {}
def singleton(cls):
def get_instance(*args, **kw):
cls_name = cls.__name__
print('===== 1 ====')
if not cls_name in instances:
print('===== 2 ====')
instance = cls(*args, **kw)
instances[cls_name] = instance
return instances[cls_name]
return get_instance
@singleton
class User:
_instance = None
def __init__(self, name):
print('===== 3 ====')
self.name = name
a1 = User('wangbm1')
a2 = User('wangbm2')
返回:
a1按顺序执行了1.2.3,但是到a2的时候instances中已经有哦cls_name了,所以不走if not 直接return了
tips:
**kargs:输入数据长度不确定,系统自动将任意长度参数用dict(字典)表示
args:输入数据长度不确定,通过args将任意长度的参数传递给函数,系统自动将任意长度参数用list(tuple定长,特殊的list)表示