设为首页 加入收藏

TOP

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


@html_tags('b')
def hello(name='Toby'):
    return 'Hello {}!'.format(name)


hello()
hello()


在装饰器中我在各个可能的位置都加上了print语句,用于记录被调用的情况。你知道他们最后打印出来的顺序吗?如果你心里没底,那么最好不要在装饰器函数之外添加逻辑功能,否则这个装饰器就不受你控制了。以下是输出结果:


begin outer function.
end of outer function
begin of inner wrapper function.
end of inner wrapper function.
<b>Hello Toby!</b>
<b>Hello Toby!</b>
(wda_python) bash-3.2$


错误的函数签名和文档


装饰器装饰过的函数看上去名字没变,其实已经变了。


import datetime


def logging(func):
    def wrapper(*args, **kwargs):
        """print log before a function."""
        print "[DEBUG] {}: enter {}()".format(datetime.now(), func.__name__)
        return func(*args, **kwargs)
    return wrapper


@logging
def say(something):
    """say something"""
    print "say {}!".format(something)


print say.__name__
print say.__doc__


运行结果:


wrapper
print log before a function.
(wda_python) bash-3.2$


为什么会这样呢?只要你想想装饰器的语法糖@代替的东西就明白了。@等同于这样的写法。
say = logging(say)


logging其实返回的函数名字刚好是wrapper,那么上面的这个语句刚好就是把这个结果赋值给say,say的__name__自然也就是wrapper了,不仅仅是name,其他属性也都是来自wrapper,比如doc,source等等。


使用标准库里的functools.wraps,可以基本解决这个问题。


import datetime
from functools import wraps


def logging(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """print log before a function."""
        print "[DEBUG] {}: enter {}()".format(datetime.now(), func.__name__)
        return func(*args, **kwargs)
    return wrapper


@logging
def say(something):
    """say something"""
    print "say {}!".format(something)


print say.__name__
print say.__doc__


运行结果:


say
say something
(wda_python) bash-3.2$


但是其实还不太完美, 因为函数的签名和源码还是拿不到


import datetime
from functools import wraps
def logging(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """print log before a function."""
        print "[DEBUG] {}: enter {}()".format(datetime.now(), func.__name__)
        return func(*args, **kwargs)
    return wrapper


@logging
def say(something):
    """say something"""
    print "say {}!".format(something)


print say.__name__
print say.__doc__


import inspect
print inspect.getargspec(say)
print inspect.getsource(say)


运行结果:


say
say something
ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)
    @wraps(func)
    def wrapper(*args, **kwargs):
        """print log before a function."""
        print "[DEBUG] {}: enter {}()".format(datetime.now(), func.__name__)
        return func(*args, **kwargs)


(wda_python) bash-3.2$


如果要彻底解决这个问题可以借用第三方包,比如wrapt, 后文有介绍


不能装饰@staticmethod 或者 @classmethod


当你想把装饰器用在一个静态方法或者类方法时,不好意思,报错了。


class Car(object):
    def __init__(self, model):
        self.model = model


    @log

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

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目