zoukankan      html  css  js  c++  java
  • 装饰器 python 你也可以叫语法糖

    1.最简单的装饰器不带入参

    def  func():

       pass

    def  decorate(func)

      def wrapper():

        return func()

      return wrapper

    使用

    @decorate

    def  aa(m):

       pass

    2.要是带参数就简单给他就是了:

    因为函数有千千万,你只管你自己的函数,别人的函数参数是什么样子,鬼知道?还好Python提供了可变参数*args和关键字参数**kwargs,有了这两个参数,装饰器就可以用于任意目标函数了。

    def  decorate(func)

      def wrapper(*args,**kwargs):

        return func((*args,**kwargs)

      return wrapper

    如何优化你的装饰器#

    嵌套的装饰函数不太直观,我们可以使用第三方包类改进这样的情况,让装饰器函数可读性更好。

    decorator.py#

    decorator.py 是一个非常简单的装饰器加强包。你可以很直观的先定义包装函数wrapper(),再使用decorate(func, wrapper)方法就可以完成一个装饰器。

    Copy
    from decorator import decorate
    
    def wrapper(func, *args, **kwargs):
        """print log before a function."""
        print "[DEBUG] {}: enter {}()".format(datetime.now(), func.__name__)
        return func(*args, **kwargs)
    
    def logging(func):
        return decorate(func, wrapper)  # 用wrapper装饰func

    你也可以使用它自带的@decorator装饰器来完成你的装饰器。

    Copy
    from decorator import decorator
    
    @decorator
    def logging(func, *args, **kwargs):
        print "[DEBUG] {}: enter {}()".format(datetime.now(), func.__name__)
        return func(*args, **kwargs)

    decorator.py实现的装饰器能完整保留原函数的namedocargs,唯一有问题的就是inspect.getsource(func)返回的还是装饰器的源代码,你需要改成inspect.getsource(func.__wrapped__)

    wrapt#

    wrapt是一个功能非常完善的包,用于实现各种你想到或者你没想到的装饰器。使用wrapt实现的装饰器你不需要担心之前inspect中遇到的所有问题,因为它都帮你处理了,甚至inspect.getsource(func)也准确无误。

    Copy
    import wrapt
    
    # without argument in decorator
    @wrapt.decorator
    def logging(wrapped, instance, args, kwargs):  # instance is must
        print "[DEBUG]: enter {}()".format(wrapped.__name__)
        return wrapped(*args, **kwargs)
    
    @logging
    def say(something): pass

    使用wrapt你只需要定义一个装饰器函数,但是函数签名是固定的,必须是(wrapped, instance, args, kwargs),注意第二个参数instance是必须的,就算你不用它。当装饰器装饰在不同位置时它将得到不同的值,比如装饰在类实例方法时你可以拿到这个类实例。根据instance的值你能够更加灵活的调整你的装饰器。另外,argskwargs也是固定的,注意前面没有星号。在装饰器内部调用原函数时才带星号。

    如果你需要使用wrapt写一个带参数的装饰器,可以这样写。

    Copy
    def logging(level):
        @wrapt.decorator
        def wrapper(wrapped, instance, args, kwargs):
            print "[{}]: enter {}()".format(level, wrapped.__name__)
            return wrapped(*args, **kwargs)
        return wrapper
    
    @logging(level="INFO")
    def do(work): pass

    关于wrapt的使用,建议查阅官方文档,在此不在赘述。

    • http://wrapt.readthedocs.io/en/latest/quick-start.html

    小结#

    Python的装饰器和Java的注解(Annotation)并不是同一回事,和C#中的特性(Attribute)也不一样,完全是两个概念。

    装饰器的理念是对原函数、对象的加强,相当于重新封装,所以一般装饰器函数都被命名为wrapper(),意义在于包装。函数只有在被调用时才会发挥其作用。比如@logging装饰器可以在函数执行时额外输出日志,@cache装饰过的函数可以缓存计算结果等等。

    而注解和特性则是对目标函数或对象添加一些属性,相当于将其分类。这些属性可以通过反射拿到,在程序运行时对不同的特性函数或对象加以干预。比如带有Setup的函数就当成准备步骤执行,或者找到所有带有TestMethod的函数依次执行等等。

    至此我所了解的装饰器已经讲完,但是还有一些内容没有提到,比如装饰类的装饰器。有机会再补充。谢谢观看。

  • 相关阅读:
    正则表达式
    HDU 2066 多源最短路
    UVA 11039 模拟
    Concrete Mathematics Chapter 1 Warmups
    List differences between JAVA and C++
    uva 11107Life Forms
    poj 1509 Glass Beads
    poj 3581
    网络流建图
    图论算法----网络流
  • 原文地址:https://www.cnblogs.com/SunshineKimi/p/10771981.html
Copyright © 2011-2022 走看看