设为首页 加入收藏

TOP

Python装饰器心得笔记(一)
2019-01-25 14:09:46 】 浏览:425
Tags:Python 装饰 心得 笔记

装饰器(Decorators)


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


概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能。


为什么需要装饰器


我们假设你的程序实现了func_enter()和func_quit()两个函数。


def func_enter():
    print "enter!"



def func_quit():
    print "enter!"  # bug here



if __name__ == '__main__':
    func_enter()
    func_quit()


运行结果:


enter!
enter!
(wda_python) bash-3.2$


但是在实际调用中, 我们发现程序出错了, 上面打印了2个enter。经过调试我们发现是func_quit()出错了


现在假如要求调用每个方法前都要记录进入函数的名称, 比如这样:


[DEBUG]: enter func_enter()
enter!
[DEBUG]: enter func_quit()
enter!


一种最直白简单的方式是这样写:


def func_enter():
    print "[DEBUG]: enter func_enter()"
    print "enter!"



def func_quit():
    print "[DEBUG]: enter func_quit()"
    print "enter!"  # bug here



if __name__ == '__main__':
    func_enter()
    func_quit()


但是很low对吧, 我们可以试着这样写:


def debug():
    import inspect
    caller_name = inspect.stack()[1][3]
    print '[BEBUG]: enter {}()'.format(caller_name)


def func_enter():
    debug()
    print "enter!"



def func_quit():
    debug()
    print "enter!"  # bug here



if __name__ == '__main__':
    func_enter()
    func_quit()


看起来会好一点, 但是每个函数都要调用一次debug()函数,还是不太够, 万一如果又改需求进出不打印调用者了, 其他地方或者函数在打印, 又要大改


怎么办呢? 这个时候装饰器就可以派上用场了


怎么写一个装饰器


我们来看一个例子



按 Ctrl+C
def debug(func):
    def wrapper():
        print '[DEBUG]: enter {}()'.format(func.__name__)
        return func()
    return wrapper


@debug
def func_enter():
    print "enter!"


@debug
def func_quit():
    print "enter!"  # bug here



if __name__ == '__main__':
    func_enter()
    func_quit()
按 Ctrl+C


运行结果:


[DEBUG]: enter func_enter()
enter!
[DEBUG]: enter func_quit()
enter!
(wda_python) bash-3.2$


这是一个最简单的装饰器, 但是有个问题, 如果被装饰的函数需要传入参数, 那么这个装饰器就坏了,因为返回的函数并不能接受参数


这里可以指定装饰器函数wrapper接受和原函数一样的参数, 比如:


#coding: utf-8


def debug(func):
    def wrapper(something):    # 这里指定一样的参数
        print '[DEBUG]: enter {}()'.format(func.__name__)
        return func(something)
    return wrapper # 返回包装过的函数


@debug
def func_enter(something):
    print "enter {}!".format(something)


@debug
def func_quit(something):
    print "enter {}!".format(something)  # bug here



if __name__ == '__main__':
    func_enter("enter_func")
    func_quit("quit_func")


运行结果:


[DEBUG]: enter func_enter()
enter enter_func!
[DEBUG]: enter func_quit()
enter quit_func!


这样解决了传参数的问题, 但是这里有个很大的问题是这里只适配了我们的func_enter和func_quit函数的参数, 如果要用来去装饰其他带参数的函数呢?


还好python提供可变参数*args和关键字参数**kwargs, 有这两个参数装饰器就可以用于任意目标函数了


#coding: utf-8


def debug(func):
    def wrapper(*args, **kwargs):    # 这里指定一样的参数
        print '[DEBUG]: enter {}()'.format(func.__name__)
        return func(*args, **kwargs)
    return wrapper # 返回包装过的函数


@debug
def func_enter(something):
&n

首页 上一页 1 2 3 4 5 6 下一页 尾页 1/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C#相等判断实例报错分析及解决 下一篇详解Python的装饰器

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目