• python 装饰器


    python 装饰器 decorator 是以函数为参数并返回函数的高阶函数。

    正如字面含义,装饰意思即对其他函数进行修饰,限制等等。

    装饰器仅仅是语法糖。 没有装饰器,一切照样可以实现,但需要多几行代码。 使用装饰器则可以帮助你编写更简洁的代码。

    1. 一个 decorator 例子

    如下的代码:delete_database() 是删除数据库的函数,因为是危险的操作,所以要对其进行修饰(/限制),只允许管理员进行这项操作。

    user = {'id': 1,'name': 'a_user','role': 'admin'}
     
    def delete_database():
        # perform deletion
        print('Database deleted!')
     
    def check_permission(func):
        def wrapper():
            if user.get('role') == 'admin':
                return func()
            else:
                raise PermissionError('Not allowed, you are not an admin!')
        return wrapper
     
    secure_delete_database = check_permission(delete_database)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    check_permission(func) 即是装饰器,如果是管理员,返回函数,允许操作,否则引发异常。

    2. 改为常见的使用 @ 的语法

    user = {'id': 1,'name': 'a_user','role': 'admin'}
    
    def check_permission(func):
        def wrapper():
            '''Hi, this is wrapper'''
            if user.get('role') == 'admin':
                return func()
            else:
                raise PermissionError('Not allowed, you are not an admin!')
        return wrapper
    
    @check_permission            # 使用 @ 语法!
    def delete_database():
        '''Delete the whole database'''
        # perform deletion
        print('Database deleted!')
     
    print(delete_database.__name__)
    print(delete_database.__doc__)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    上面的代码存在一个问题,就是最后两个print 输出的都是 wrapper 函数的信息:

    wrapper
    Hi, this is wrapper
    
    • 1
    • 2

    解决方法就是 decorator 里再加 decorator:

    import functools   # 1 导入 package
        
    user = {'id': 1,'name': 'a_user','role': 'admin'}
    
    def check_permission(func):
        @functools.wraps(func)  # 2 对 wrapper 加修饰器
        def wrapper():
            '''Hi, this is wrapper'''
            if user.get('role') == 'admin':
                return func()
            else:
                raise PermissionError('Not allowed, you are not an admin!')
        return wrapper
    
    @check_permission
    def delete_database():
        '''Delete the whole database'''
        # perform deletion
        print('Database deleted!')
     
    print(delete_database.__name__)
    print(delete_database.__doc__)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    最后两行变为正确的输出:

    delete_database
    Delete the whole database
    
    • 1
    • 2

    3. 装饰带有参数的函数

    装饰带有参数的函数写法例子,这种方法不通用,其他函数想要使用此装饰器,也必须一样加参数:

    import functools
     
    user = {'user_name':'jose123', 'access_level':'admin'}
     
    def user_has_permission(func):
        @functools.wraps(func)
        def secure_func(arg):
            """Hi, this is wrapper secure_func!"""
            if user.get('access_level') == 'admin':
                return func(arg)
        return secure_func
     
    @user_has_permission  
    def my_function(panel):
        '''retrieves admin password'''
        return f'Password for {panel} panel is 1234.'
     
    print(my_function("Shipping"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用 *args**kwargs 两种可变参数,使用单个星号参数,可以接受任意数量的位置参数,使用双星号,可以接受任意数量的命名参数:

    import functools
     
    user = {'user_name':'jose123', 'access_level':'admin'}
     
    def user_has_permission(func):
        @functools.wraps(func)
        def secure_func(*args, **kwargs):
            """Hi, this is wrapper secure_func!"""
            if user.get('access_level') == 'admin':
                return func(*args, **kwargs)
        return secure_func
     
    @user_has_permission  
    def my_function(panel):
        '''retrieves admin password'''
        return f'Password for {panel} panel is 1234.'
        
    @user_has_permission
    def another():
        pass
     
    print(my_function("Shipping"))  # Password for Shipping panel is 1234.
    print(another())  # None
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4. 装饰器带参数,需要定义 3 级函数:

    import functools
    
    user = {'user_name':'jose123', 'access_level':'user'}
    
    def user_has_permission(access_level):
        def my_decorator(func):
            @functools.wraps(func)
            def secure_func(panel):
                """Hi, this is wrapper secure_func!"""
                if user.get('access_level') == access_level:
                    return func(panel)
            return secure_func
        return my_decorator
     
    @user_has_permission('user')  
    def my_function(panel):
        '''retrieves admin password'''
        return f'Password for {panel}  panel is 1234.'
    
    print(my_function("Shipping"))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    java计算机毕业设计的健身房管理系统源码+mysql数据库+系统+lw文档+部署
    转行做程序员,从月薪5k到30k,45岁测试员道出了一路的心酸
    【华为OD机试真题 python】 靠谱的车【2022 Q4 | 100分】
    路由进阶:route-policy实验配置
    SpringBoot的流浪宠物系统
    数据结构2月22日
    石头剪刀布游戏(C语言)
    基于R、Python的Copula变量相关性分析及AI大模型应用
    springboot自动配置原理
    PyTorch深度学习实战(16)——面部关键点检测
  • 原文地址:https://blog.csdn.net/ftell/article/details/125607340