zoukankan      html  css  js  c++  java
  • 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

    更多关于装饰器的说明

    关于装饰器的实例

  • 相关阅读:
    MVC3 的路由Test
    表连接
    Moq MVC 初窥门径(一)
    FATAL ERROR: JS Allocation failed process out of memory
    版本号的意义
    JavaScript 类型的隐式转换
    翻译foreach语句
    一次http请求的全过程(附mmap文件下载)
    AOP学习笔记
    Kindle3之中文乱码问题
  • 原文地址:https://www.cnblogs.com/autoria/p/6158174.html
Copyright © 2011-2022 走看看