python - 修饰函数

Python 装饰器(Decorator) ,名字叫装饰器,功能自然对应于设计模式中的装饰者模式(代理模式)。

写法上,很像 java 中的函数注解,实际上,功能也大致一样。

简单说:就是在调用函数的时候,可以在在调用之前,加一点逻辑,调用完加一些逻辑,出现异常时加一些逻辑。

用途很多:入参的校验,异常处理,返回值格式转换,等等等。

装饰器

不带参数的装饰者

# 固定的写法
def logger(func):

    # 内部函数
    def debug(a, b):
        # try...catch... 经典代码结构
        try:
            if b == 0:
                raise Exception('by zero!')
            return func(a, b)
        except Exception as e:
            print(e)
            raise e

    return debug


@logger
def div(a,b):
    return a/b


print(div(1, 1))

带参数的装饰者


def logger(level):

    # 固定的写法
    def decorator(func):

        # 内部函数
        def debug(a, b):
            # try...catch... 经典代码结构
            try:
                if b == 0:
                    raise Exception('by zero!')
                return func(a, b)
            except Exception as e:
                print(e)
                raise e

        # 根据入参,选择对应的处理程序
        if level == 'debug':
            return debug
        else:
            raise Exception('level is undefined!')

    return decorator


@logger('debug')
def div(a,b):
    return a/b


print(div(1, 1))

反射相关

看前面两个案例,会产生几个问题:

一个通用的装饰者要怎么写?该如何获取代码本身的信息呢?

比如说日志:我们至少要知道,代码报错时,它的函数名是啥,入参值是啥。

注意:下面代码有些是通过解析注解实现的,注解不是百分百可靠的
比如:返回值注解填 int,函数实际可以返回 str,这种挂羊头卖狗肉的代码,代码只会警告,但是不影响执行

import inspect


def get_arg_names(func):
    # 使用inspect.signature获取函数签名
    sig = inspect.signature(func)
    # 使用Parameter.name属性获取参数名
    return [param.name for param in sig.parameters.values()]

def get_return_type(func):
    # 使用signature来获取函数签名
    sig = inspect.signature(func)
    # 使用return_annotation来获取函数返回值注解
    return_annotation = sig.return_annotation
    # 如果返回值注解是一个类型提示,我们可以通过__origin__获取原始类型
    if hasattr(return_annotation, '__origin__'):
        return return_annotation.__origin__
    return return_annotation

def get_function_source(func):
    # 获取原始函数对象
    original = func.__wrapped__ if hasattr(func, '__wrapped__') else func

    # 获取原始函数的源代码信息
    print(inspect.getsourcelines(original)[0])

    # 获取原始函数的源代码行号
    print(inspect.getsourcelines(original)[1])


# 固定的写法
def logger(func):
    # 内部函数
    def debug(*args, **kwargs):
        # try...catch... 经典代码结构
        try:
            # 获取函数名
            print(func.__name__)

            # 获取参数名
            print(get_arg_names(func))

            # 获取文件信息
            get_function_source(func)

            # 获取参数值
            print(args)

            print(kwargs)

            return func(*args, **kwargs)
        except Exception as e:
            print(e)
            raise e

    return debug


@logger
def div(a, b):
    return a / b


print(div(1, 1))

posted on   疯狂的妞妞  阅读(25)  评论(0编辑  收藏  举报

(评论功能已被禁用)
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示