python的闭包和装饰器

本文详细介绍了Python中的闭包和装饰器概念,通过实例展示了它们的工作原理。闭包是一种特殊的内嵌函数,可以记住外部函数的作用域。装饰器则用于在不修改原函数代码的情况下,增加额外功能,如计时、权限检查等。文章通过多个装饰器示例,包括参数化装饰器和类装饰器,阐述了装饰器的使用和实现方式,并讨论了装饰器的执行时机。此外,还探讨了如何使用装饰器进行多次装饰以及在不同场景下的应用。
摘要由CSDN通过智能技术生成

closure

https://www.programiz.com/python-programming/closure

def get_config_table():
    cfg = {'a':1, 'b':2}
    return cfg

def get_config_index():
    config_table = get_config_table()
    def wrapper(cfg_name):
        return config_table.get(cfg_name, 'NULL')
    return wrapper
f=get_config_index()
f('a')
1

decorator

decorator pattern

在这里插入图片描述

Simple demo

from datetime import datetime
from functools import wraps
def time_this(func):
    #@wraps(func)
    def wrapper(*args, **kwargs):
        begin = datetime.now()
        res = func(*args, **kwargs)
        end = datetime.now()
        print("{} costs:{}".format(func.__name__, end - begin))
        return res
    return wrapper

@time_this
def count(num):
    import time
    time.sleep(num)

def count1(num):
    import time
    time.sleep(num)
count1 = time_this(count1)

count(2)
count1(2)
class Foo:
    @time_this
    def _sub(self, n):
        print("_sub")
    @time_this
    def foo1(self, num):
        self._sub(9)
        print("Foo.foo1")
f = Foo()
f.foo1(2)
count costs:0:00:02.000687
count1 costs:0:00:02.000561
_sub
_sub costs:0:00:00.000988
Foo.foo1
foo1 costs:0:00:00.000988

Discussion

  • decorating happens durning import

  • understand it by count = time_this(count), syntactic suger make it easy to use but far to understand

  • cellphone case

  • make a cellphone

  • make cellphone wrapper

  • wrap—>return a closure which stores the function

  • a case of closure

With parameter

Define

from functools import wraps

def requires_permission(sPermission):                            
    def decorator(fn):
        @wraps(fn)
        def decorated(*args,**kwargs):       
            print("by function decorator")
            lPermissions = get_permissions(current_user_id())     
            if sPermission in lPermissions:                       
                return fn(*args,**kwargs)                         
            raise Exception("You need '{}' permission".format(sPermission))                  
        return decorated                                          
    return decorator       

def get_permissions(iUserId):
    return {1: ('logged_in', 'premium_member')}[iUserId]
                         
@requires_permission('administrator')
def delete_user(iUserId):
    pass

@requires_permission('logged_in')
def new_game():
    pass

@requires_permission('premium_member')
def premium_checkpoint():
    pass

def current_user_id():
    return 1

Test

def test():
    from functools import partial
    for fun in (partial(delete_user, 1), new_game, premium_checkpoint):
        try:
            fun()
        except Exception as e:
            print("test {} with error '{}'".format(fun, str(e)))
        else:
            print("test {} OK".format(fun))

test()
test functools.partial(<function require_permission_by_class_v1.__call__.<locals>.wrapper at 0x00000215357198B8>, 1) with error 'permission denied'
test <__main__.require_permission_by_class object at 0x0000021534BA32C8> OK
test <__main__.require_permission_by_class object at 0x0000021534BA3FC8> OK

Decorator as class

class require_permission_by_class(object):
    def __init__(self, permission, func):
        self._func = func
        self._permission = permission
    def __call__(self, *args, **kwargs):
        print("by class for {}".format(self._func.__name__))
        lPermissions = get_permissions(current_user_id())     
        if self._permission in lPermissions:                       
            return self._func(*args,**kwargs)                         
        raise Exception("permission denied")
        
def get_permissions(iUserId):
    return {1: ('logged_in', 'premium_member')}[iUserId]
                         
def delete_user(iUserId):
    pass
delete_user=require_permission_by_class('administrator', delete_user)


def new_game():
    pass
new_game=require_permission_by_class('logged_in', new_game)


dec1=lambda f:require_permission_by_class('premium_member', f)
@dec1
def premium_checkpoint():
    pass

#premium_checkpoint=require_permission_by_class('premium_member', premium_checkpoint)

def current_user_id():
    return 1

def test():
    from functools import partial
    for fun in (partial(delete_user, 1), new_game, premium_checkpoint):
        try:
            fun()
        except Exception as e:
            print("test {} with error '{}'".format(fun, str(e)))
        else:
            print("test {} OK".format(fun))

test()
by class for delete_user
test functools.partial(<__main__.require_permission_by_class object at 0x0000021534C20348>, 1) with error 'permission denied'
by class for new_game
test <__main__.require_permission_by_class object at 0x0000021535441948> OK
by class for premium_checkpoint
test <__main__.require_permission_by_class object at 0x0000021534D18C08> OK

Another way

class require_permission_by_class_v1(object):
    def __init__(self, permission):
        self._permission = permission
    def __call__(self, func, *args, **kwargs):
        def wrapper(*args, **kwargs):
            print("by class v1 for {}".format(func.__name__))
            lPermissions = get_permissions(current_user_id())     
            if self._permission in lPermissions:                       
                return self._func(*args,**kwargs)
            raise Exception("permission denied")
        return wrapper

@require_permission_by_class_v1('administrator')
def delete_user(iUserId):
    pass
#delete_user=require_permission_by_class_v1('administrator')(delete_user)
Test
test()
by class v1 for delete_user
test functools.partial(<function require_permission_by_class_v1.__call__.<locals>.wrapper at 0x0000021534F9FCA8>, 1) with error 'permission denied'
by class for new_game
test <__main__.require_permission_by_class object at 0x0000021535441948> OK
by class for premium_checkpoint
test <__main__.require_permission_by_class object at 0x0000021534D18C08> OK

decorate multiple times

def retry(nums):
    def decorator(fun):
        def wrapper(*args, **kwargs):
            for i in range(nums):
                try:
                    return fun(*args, **kwargs)
                except Exception as e:
                    print("{} fail{}".format(fun.__name__, ' retry...' if i < nums -1 else ''))
        return wrapper
    return decorator

@time_this
@retry(3)
def must_be_fail():
    raise Exception("bad guy")

must_be_fail()

Summary

  • Add aditional function before and after function
  • Know the classic usage cases to give you enlightenment:
    • log
    • time cost
    • exception handle
    • permission manager
    • retry

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值