python 装饰器/函数装饰器/类装饰器

 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)

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值