Python中装饰器的用法总结:
'''
Author: Hollis23
Date: 2021-10-19 15:01:29
LastEditTime: 2021-10-20 09:27:56
LastEditors: Hollis23
Description: v0.0
FilePath: /mmdetection/tests/test_decorator/1.py
'''
import functools
import time
from typing import AsyncGenerator
'''
@符号就是装饰器语法糖
它放在一个函数开始定义的地方,就像一顶帽子一样戴在这个函数的头上,和这个
函数绑定在一起。在我们调用这个函数的时候,第一件事并不是执行这个函数,而是
将这个函数作为参数传入他头顶这顶帽子,这顶帽子我们称为装饰函数或装饰器
'''
def logger(func):
def wrapper(*args, **kw):
print('Prepare to calculate: {} func!'.format(func.__name__))
func(*args, **kw)
print('claculate Done!')
return wrapper
@logger
def add(x, y):
print('{} + {} = {}'.format(x, y, x+y))
def timer(func):
def wrapper(*args, **kw):
t1 = time.time()
func(*args, **kw)
t2 = time.time()
cost_time = t2 - t1
print('take {} seconds'.format(t2 - t1))
return wrapper
@timer
def want_sleep(sleep_time):
time.sleep(sleep_time)
def say_hello(country):
def wrapper(func):
def deco(*args, **kw):
if country == 'china':
print('你好!')
elif country == 'american':
print('Hello!')
else:
return
func(*args, **kw)
return deco
return wrapper
@say_hello('american')
def american():
print('I coming from America!')
@say_hello('china')
def china():
print('I coming from China!')
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__))
return self.func(*args, **kwargs)
@logger
def say(something):
print('say {}!'.format(something))
'''
上面不带参数的例子只能打印INFO级别的日志,正常情况下,我们还要打印
DEBUG,WARNING等级别的日志。这就需要给类装饰器传入参数,给这个函数
指定级别了。
带参数和不带参数的装饰器有很大的不同:
__init__: 不再接收被装饰函数,而是接收传入参数
__call__: 接收被装饰函数,实现装饰逻辑
'''
class logger(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print('[{level}]: the function {func}() is running...'
.format(level=self.level, func=func.__name__))
func(*args, **kwargs)
return wrapper
@logger(level='WARNING')
def talk(something):
print('say {}!'.format(something))
if __name__ == '__main__':
talk('hello')
'''
绝大多数装饰器都是基于函数和闭包实现,但这并不是制造装饰器的唯一方法
Python对某个对象是否能通过装饰器形式使用(当做装饰器使用)只有一个要求:decorator必须
是一个‘可被调用(callable)的对象’。
这个callable对象,我们最熟悉的就是函数,类也可以是callable对象,只要实现了__call__函数
,还有比较少人使用的偏函数也是callable对象。
'''
class DelayFunc:
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Waig 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):
return functools.partial(DelayFunc, duration)
@delay(duration=2)
def add(a, b):
return a + b
instances = {}
def singleton(cls):
def get_instance(*args, **kwargs):
cls_name = cls.__name__
print('============1============')
if not cls_name in instances:
print('++++++++2+++++++++++')
instance = cls(*args, **kwargs)
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
class Student(object):
def __init__(self, name, age=None):
self.name = name
self.age = age
XiaoMing = Student('小明')
XiaoMing.age = 25
XiaoMing.age
del XiaoMing.age
class Student(object):
def __init__(self, name):
self.name = name
self.name = None
def set_age(self, age):
if not isinstance(age, int):
raise ValueError('输入不合法:年龄必须为数值!')
if not 0 < age < 100:
raise ValueError('输入不合法:年龄范围必须0-100!')
self._age = age
def get_age(self):
return self._age
def del_age(self):
self._age = None
XiaoMing = Student('小明')
XiaoMing.set_age(25)
XiaoMing.get_age()
XiaoMing.del_age()
class Student(object):
def __init__(self, name):
self.name = name
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if not isinstance(value, int):
raise ValueError('年龄必须为数字')
if not 0 < value < 100:
raise ValueError('年龄超出正常范围')
self._age = value
@age.deleter
def age(self):
del self._age