python 装饰器(上)

装饰器(上)

python 的装饰器属于函数式编程的范畴。维基百科可以点击链接看看维基百科上的解释。没错,我看得一脸懵逼。就目前学习的而言,我把它总结为面向函数的编程。这样就好理解一下,当然实际上肯定有所偏颇。在面向过程中,函数是组成过程的单位。面对对象的基石是对象。而函数式这种范式下函数是基石,当做变量的存在。

装饰器的初衷

首先装饰这个词可以理解一下。装饰不就是在原有的物品上加以修饰,添加一些看起来不是特别重要的美化功能。那么对应于编程来说,装饰器就是修饰原本函数用的一种方法了。装饰器模式不改变原有的业务逻辑,对代码没有侵略性。所以常常可以用来做日志统计,异常捕获,web的权限校验等操作。

装饰器示例

我们想要在函数运行前打印日志会这么做:
原函数:

 def now():
    print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

装饰器:

def log(func):
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper

装饰器修饰原函数语法:

@log
def now():
    print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

@log 是什么鬼呢?其实他就是个语法糖 概念点击链接。
相当于执行了

now = log(now)

那么这时候的now是什么?参看上面那就是return的 wrapper。

import time


def log(func):
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper


def now():
    print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())


if __name__ == '__main__':
    f = log(now())
    print f
    f()

输出:

<function wrapper at 0x1042232a8>
call now():
2018-08-03 09:42:19

Process finished with exit code 0

可以看到返回的f就是wrapper。如果我们这个时候调用和装饰器是一样的。注意在使用装饰器的时候他已经执行完了赋值返回wrapper这一段。所以如果是在:

def log(func):
    # do something before function call ---1
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper

上面的do something 会在调用前执行。
至此我们所认识的最简单的装饰器就完成了。

函数带参数

函数原本所传的参数需要和返回的wrapper一致。这个容易理解,因为实际在调用的时候实际上是调用wrapper。这里传参是也有两种写法,一种是对应上,log函数,一种是使用省略语法,可以兼容所有的函数。

def log(func):
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper


def log_1(func):
    def wrapper(a, b, c):
        print 'call %s():' % func.__name__
        return func(a, b, c)
    return wrapper


@log
def add(a, b, c):
    print a + b + c


@log_1
def add_1(a, b, c):
    print a + b + c


if __name__ == '__main__':
    add(1, 2, 3)
    add_1(1, 2, 3)

除了这种使用我们还可以在wrapper中新增加参数传入到函数中。

def add_one_param(func):
    def wrapper(a, b, c):
        print 'call %s():' % func.__name__
        d = 100
        return func(a, b, c, d)
    return wrapper


@add_one_param
def add_one_more_param(a, b, c, d):
    print a + b + c + d

if __name__ == '__main__':
    add_one_more_param(1, 2, 3)

输出:

call add_one_more_param():
106

如果把参数改为如下也是没毛病的:

def add_one_param(func):
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        d = 100
        return func(d, *args, **kw)
    return wrapper

装饰器带参数

装饰器带参数一般而言是用于区分装饰器的功能。比如一个装饰器是日志功能。日志有等级之分,则可以在装饰器上传入参数区分打印。

语法

需要在原本装饰器外在包装一层:

def log(log_level):
    def decorator(func):
        def wrapper(*args, **kw):
            if log_level == WARNING_LEVEL:
                print WARNING_LEVEL
            elif log_level == ERROR_LEVEL:
                print ERROR_LEVEL
            print 'call %s():' % func.__name__
            return func(*args, **kw)
        return wrapper
    return decorator

@log(ERROR_LEVEL)
def add(a, b, c):
    print a + b + c

if __name__ == '__main__':
    add(1, 2, 3)

输出:

error
call add():
6

当这样调用的时候,很明显参数已经传入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值