装饰器
在定义类时候, 使用静态方法 @staticmethod, 类方法 @classmethod 上面的 @就是装饰器之一
引入装饰器
不想做饭和洗碗
def eat():
print('我正在吃饭')
def a1(b1): # b1是函数
def c1():
print('把饭做好了')
b1()
print('把碗洗好')
return c1
d1 = a1(eat) # 传入函数
d1()
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值
也是一个函数对象
它经常用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景
使用与定义装饰器
# 这个函数并没有发生变化 只是需要把顺序往上调整
def a1(b1): # b1是传入参数, 这个参数作为函数传入, 表示额外功能 | a1 就是装饰器 (高阶函数)
def c1():
print('把饭做好了')
b1()
print('把碗洗好')
return c1
# 这个函数需要在头加上 引用装饰器
@a1 # a1 引用装饰器
def eat():
print('我正在吃饭')
# 调用直接使用 主要的函数即可 无需再调用 a1, 并传入值
# 使用装饰器
eat()
print(eat.__name__) # c1
但打印 eat的名字时, 返回的却不是其本身 eat 而是装饰器名字
优化, 使其 打印eat的名字时, 返回的也是eat
# 导入包装
from functools import wraps
# 在装饰器函数下进行处理 使用 @wraps(函数)
def a1(b1): # b1是传入参数, 这个参数作为函数传入, 表示额外功能 | a1 就是装饰器 (高阶函数)
@wraps(b1)
def c1():
print('把饭做好了')
b1()
print('把碗洗好')
return c1
练习 工作与日志
import time
print('-' * 80)
# 记录日志专用
def loger(func):
@wraps(func)
def a2():
print('日志时间', time.time())
func()
return a2
@loger
def work():
print('我在工作')
work()
print(work.__name__)
装饰器给定参数
# 记录日志专用2
# 装饰器需要通用 可能需要 日志类型(级别) 日志保存位置
# 先给予工作的注入参数
def loger2(func):
@wraps(func)
def a2(*args, **kwargs):
print('日志时间', time.time())
func(*args, **kwargs)
return a2
@loger2
def work2(name): # 当前 work具有参数, 可能多个
print(f'{name}在工作')
work2('小明')
print(work2.__name__)
# 在上一层加嵌套函数
def b2(filePath='06.log'):
def loger2(func):
@wraps(func)
def a2(*args, **kwargs):
print('日志时间', time.strftime('%H:%M:%S', time.localtime()), file=open(filePath, 'a', encoding='utf-8'))
func(*args, **kwargs)
return a2
return loger2
@b2('06-work2.log')
def work2(name1, name2): # 当前 work具有参数, 可能多个
print(f'{name1}和{name2}在工作')
work2('小明', '小花')
print(work2.__name__)
使用类进行做装饰器
# 使用类做装饰器
class Logs:
def __init__(self, logLevel='info', filePath='06.class-logs.log'):
self.logLevel = logLevel
self.filePath = filePath
def __call__(self, func): # 定义装饰器
@wraps(func)
def a2(*args, **kwargs):
f = open(self.filePath, 'a', encoding='utf-8')
print(f'[{self.logLevel}] 日志时间', time.strftime('%H:%M:%S', time.localtime()), file=f)
func(*args, **kwargs)
return a2
# 使用类做装饰器
@Logs(logLevel='info', filePath='06.class-logs.log')
def work3(name1, name2): # 当前 work具有参数, 可能多个
print(f'{name1}和{name2}在工作')
work3('张三', '李四')
print(work3.__name__)
偏函数
Python的functools 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的
偏函数和数学意义上的偏函数不一样。
如 int
# 偏函数
from functools import partial
a4 = int('13', 16)
print(a4, type(a4)) # 16进制数字字符串转为 10进制数字 | 19
b4 = int('13', 8)
print(b4, type(b4)) # 8进制数字字符串转为 10进制数字
c4 = int('1001', 2)
print(c4, type(c4)) # 2进制数字字符串转为 10进制数字
# 如果每一次都需要进行转可能不方便
bin_to_dec = lambda _: int(_, 2)
print(bin_to_dec('1001'))
# 可以使用这样方式 偏函数 是这个好还是lambda 把一些函数的参数进行固定, 可以使一些函数的参数进行固定
bin_to_dec = partial(int, base=2)
print(bin_to_dec('1001'))