python函数装饰器和类装饰器笔记.
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author:ivan
@file: decorators.py
@version:
"""
from functools import wraps
# 装饰器: 目的是为了给函数添加附加功能
# 1. 不带参数装饰器
# 此方式, 将会把被装饰的函数对象作为第一个参数(形参)传入装饰函数中,
# 被装饰的函数的args和kwargs参数将会自动传入装饰器里面的函数中
def de1(func):
def wrap(*args, **kwargs):
print('func name: ', func.__name__)
print('args: ', args)
print('kargs: ', kwargs)
return func(*args, **kwargs)
return wrap
@de1
def f1(a, b=3):
print(a)
f1(33, b=33)
# 输出结果
# func name: f1
# args: (33,)
# kargs: {'b': 33}
# 33
# f1(33, b=33)运行过程为
# --->>>> 注意: 不是 de1(f1(33, b=33)), 因为装饰器是把被装饰的函数作为参数传给装饰器, 最后返回来的是一个函数
# de1(f1)(33, b=33)
# 2. 带参数的函数装饰器
def de2(*args, **kwargs):
# 不使用装饰器参数
print(f'args: {args}')
print(f'kwargs: {kwargs}')
def decorator(func):
def wrap(*fargs, **fkwargs):
print('func name: ', func.__name__)
print('fargs: ', fargs)
print('fkwargs: ', fkwargs)
return func(*fargs, **fkwargs)
return wrap
return decorator
@de2(33, a=44)
def f2(a, b=55):
"""
f2
"""
print(f'{a}: {b}')
f2(123, b=33222)
# 装饰器会导致被装饰的函数的元信息丢失, 如果要保持, 可以使用装饰器wraps, 见下例子
print(f2.__name__) # 输出 wrap
print(f2.__doc__) # 输出 None
# 输出结果
# args: (33,)
# kwargs: {'a': 44}
# func name: f2
# fargs: (123,)
# fkwargs: {'b': 33222}
# 123: 33222
# 运行过程
# 不是de2(33, a=44)(f2(123, b=33222))
# de2(33, a=44)(f2)(123, b=33222)
def de2(*args, **kwargs):
# 不使用装饰器参数
print(f'args: {args}')
print(f'kwargs: {kwargs}')
def decorator(func):
# 使用wraps可以保持被装饰函数的元信息
@wraps(func)
def wrap(*fargs, **fkwargs):
print('func name: ', func.__name__)
print('fargs: ', fargs)
print('fkwargs: ', fkwargs)
return func(*fargs, **fkwargs)
return wrap
return decorator
@de2(33, a=44)
def f2(a, b=55):
"""
f2
"""
print(f'{a}: {b}')
f2(123, b=33222)
print(f2.__name__) # 输出 f2
print(f2.__doc__) # 输出 f2
def de22(*args, **kwargs):
# 使用装饰器参数
print(f'args: {args}')
print(f'kwargs: {kwargs}')
f = 343
def decorator(func):
def wrap(*fargs, **fkwargs):
# 可以直接引用,例如print(args), 但是使用nonlocal声明后, 才能对args, f进行赋值操作
nonlocal args, f
print(f'args: {args}')
b = kwargs.get('b')
b = b + 33
kwargs['b'] = b
args = 44
f = 33
print(f'kwargs: {kwargs}')
print('func name: ', func.__name__)
print('fargs: ', fargs)
print('fkwargs: ', fkwargs)
return func(*fargs, **fkwargs)
return wrap
return decorator
@de22(33, b=3)
def f22(a, b=55):
print(f'{a}: {b}')
f22(123, b=33222)
# 输出结果
# args: (33,)
# kwargs: {'b': 3}
# args: (33,)
# kwargs: {'b': 36}
# func name: f22
# fargs: (123,)
# fkwargs: {'b': 33222}
# 123: 33222
def de3(a):
# 可以看作是de2的简单版本, 可以直接这样写
def decorater(func):
return func
return decorater
@de3(33)
def f3(a, b=33):
print(f'{a}-{b}')
f3(11, b=333)
# 输出结果
# 11-333
# 运行过程
# de3(33)(f3)(11, b=333)
# 类装饰器
# 1.不带参数类装饰器
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
print(f'func name: {self._func}')
self._func()
@Foo
def f5():
print(334)
f5()
# 输出
# func name: <function f5 at 0x7f864aa25ea0>
# 334
# 运行过程
# Foo(f5)()
# 2.带参数的类装饰器
class Foo2(object):
def __init__(self, *args, **kwargs):
# 接收Foo2(123, b=44)里面的参数
self.args = args
self.kwargs = kwargs
# def __call__(self, func):
# # 狸猫换太子, 更换被装饰的函数
# def f(*args, **kwargs):
# print(args)
# return f
def __call__(self, func):
def wraps(*args, **kwargs):
# 接收f6(1234, d=777)里面的参数
return func(*args, **kwargs)
return wraps
@Foo2(123, b=44)
def f6(c, d=33):
print(f'{c}:{d}')
f6(1234, d=777)
# 运行过程
# Foo2(123, b=44)(f6)(1234, d=777)