Python中的装饰器

虽然可以通过元组实现相关的功能,但是因为实际中的使用需求,最终实现了装饰器。

刚开始python仅仅支持@staticmethod一类的装饰器,后来才觉得应该广泛地支持decorator,@这个符号一开始参考自java annotation,Barry Warsaw 称之为pie-decorator,就像python的第一个音节,而且@看起来也像一个派。

其实decorator这个名字常常被人诟病,因为它包含了太多含义,比如在编译领域表示一个已经被标记的语法树。设计之初考虑了很多内容比如好看好记易用使用等等,考虑了很多用例,总之得出现在的用法是很科学的。

现在的用法:

函数装饰器

顺序

多个decorator使用就近原则,这个来自于数学符号的习惯。

语法

一封邮件里Guido提出了他对@decorator限制声明形式的看法

后来支持了

@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
    pass

相当于
func = decomaker(argA, argB, ...)(func)

讨论于邮件

位置

decorator也经过很多讨论才得到今天的形式

示例

1.让一个function在退出时被执行

def onexit(f):
    import atexit
    atexit.register(f)
    return f

@onexit
def func():
    ...

2.singleton instance

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...

3.向函数添加属性

def attrs(**kwds):
    def decorate(f):
        for k in kwds:
            setattr(f, k, kwds[k])
        return f
    return decorate

@attrs(versionadded="2.2",
       author="Guido van Rossum")
def mymethod(f):
    ...

4.检查函数接受参数和返回值的类型

def accepts(*types):
    def check_accepts(f):
        assert len(types) == f.func_code.co_argcount
        def new_f(*args, **kwds):
            for (a, t) in zip(args, types):
                assert isinstance(a, t), \
                       "arg %r does not match %s" % (a,t)
            return f(*args, **kwds)
        new_f.func_name = f.func_name
        return new_f
    return check_accepts

def returns(rtype):
    def check_returns(f):
        def new_f(*args, **kwds):
            result = f(*args, **kwds)
            assert isinstance(result, rtype), \
                   "return value %r does not match %s" % (result,rtype)
            return result
        new_f.func_name = f.func_name
        return new_f
    return check_returns

@accepts(int, (int,float))
@returns((int,float))
def func(arg1, arg2):
    return arg1 * arg2

5.为一个类实现一系列特定的接口

def provides(*interfaces):
     """
     An actual, working, implementation of provides for
     the current implementation of PyProtocols.  Not
     particularly important for the PEP text.
     """
     def provides(typ):
         declareImplementation(typ, instancesProvide=interfaces)
         return typ
     return provides

class IBar(Interface):
     """Declare something about IBar here"""

@provides(IBar)
class Foo(object):
        """Implement something here..."""

参考:https://www.python.org/dev/peps/pep-0318/

类装饰器

metaclass会被继承,而装饰器不会被继承,所以我们实现了类装饰器来应对对单个类的特定使用。唯一的不同之处是一个作用于类,一个作用于函数。

 

 

另一篇参考:http://thecodeship.com/patterns/guide-to-python-function-decorators/

内容比其他教程没太多变化,主要是看懂了

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

def strong_decorate(func):
    def func_wrapper(name):
        return "<strong>{0}</strong>".format(func(name))
    return func_wrapper

def div_decorate(func):
    def func_wrapper(name):
        return "<div>{0}</div>".format(func(name))
    return func_wrapper

定义的三个装饰器作用到一个函数上

@div_decorate
@p_decorate
@strong_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

print get_text("John")

# Outputs <div><p><strong>lorem ipsum, John dolor sit amet</strong></p></div>

不如写成

def tags(tag_name):
    def tags_decorator(func):
        def func_wrapper(name):
            return "<{0}>{1}</{0}>".format(tag_name, func(name))
        return func_wrapper
    return tags_decorator

@tags("p")
def get_text(name):
    return "Hello "+name

print get_text("John")

# Outputs <p>Hello John</p>

func_wrapper就相当于“函数的(标签)包装纸”,tags_decorator相当于"标签的包装工",tags就是一个“包装工的生成器”。

另一部分内容就是老生常谈的__name__ __doc__ __module__会被最接近func的wrapper给替换,为此使用@functools.wraps(func)夹在decorator和wrapper之间,python就会帮你复制一下。

大概像这样

def tags(tag_name):
    def tags_decorator(func):
        @functools.wraps(func)
        def func_wrapper(name):
            return "<{0}>{1}</{0}>".format(tag_name, func(name))
        return func_wrapper
    return tags_decorator

 

 

更多关于装饰器的说明

关于装饰器的实例

posted @ 2016-12-10 20:23  autoria  阅读(279)  评论(0编辑  收藏  举报