python装饰器的理解

python装饰器(Decorator)是什么:

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

本质上python装饰器是一个能够返回函数的高阶函数。是将原函数作为参数传递到装饰器方法中,在装饰器中进行其他功能的开发,然后将包装后的方法进行返回。执行起来就是在执行包装后的方法。

举个例子来说,我想在某段代码上新增日志功能,但是原有代码不想做更改,这样的话装饰器就派上用场了,代码如下:

# 日志装饰器
def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

# 原有方法
@log
def now():
    print('2015-3-25')

# 调用now方法
now()

# 运行结果:
# call now():
# 2015-3-25

可以明显看到,原函数只是打印一个日期字符串,调用now()函数的原代码也没有任何变化。只是新增了log()函数,将其作为装饰器放到原有业务代码上,调用结果就发生了变化。首先执行了 print('call %s():' % func.__name__) 这句代码,然后才执行now()函数原有的业务逻辑,输出日期字符串。

log()函数是一个接收参数和返回值都是函数的函数,接收的函数就是装饰器要修饰的函数,返回值是修饰后的包装函数。所以表面调用的是now()函数而实际是在调用装饰器中wrapper()函数。

三层嵌套的装饰器:

import functools

# 第一层接收装饰器信息
def log(text):
    # 第二层接收目标函数
    def decorator(func):
        # 将原方法的文档__name__等属性赋值给装饰器
        @functools.wraps(func)
        # 第三层接收*args, **kw
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

@log('execute')
def now():
    print('2015-3-25')

第一层接收的参数是装饰器的参数,上面例子中就是'execute',后两层代码与上面第一个例子相同。

上一段叙述中有一个问题,就是调用now()时实际调用的是wrapper()函数,这样如果打印__name__属性结果是wrapper,而调用的是now(),这样如果有依赖这个函数的__name__属性实现的函数就不能正确执行,为了避免这个问题产生引入了@functools.wraps(func)这句代码,它的作用是将原方法的__name__等属性复制到装饰器中,这样就保证了依赖原函数__name__等属性的方法也可以正常使用。

一个有趣的例子:

用装饰器实现单例模式:

def singleton(cls, *args, **kw):  
    instances = {}  
    def _singleton():  
        if cls not in instances:  
            instances[cls] = cls(*args, **kw)  
        return instances[cls]  
    return _singleton  

@singleton  
class MyClass4(object):  
    a = 1  
    def __init__(self, x=0):  
        self.x = x  

这是我在网上看到的一个例子,感觉这种方式挺有意思,就记录下来了。其中MyClass4这个类并不知道自己是单例的,通过装饰器的修饰,每次创建实例都是通过单例模式获取的。这样就可以肆无忌惮的“创建”对象了~

补充说明:装饰器实现的单例模式目前有几个问题暂时未解决,后续补充

 

最后附上参考博客:廖雪峰的官方网站python面试大全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值