zoukankan      html  css  js  c++  java
  • [Python]装饰器总结

    目录

    闭包

    装饰器

    1.  简单装饰器
    2. 修饰带参函数的装饰器
    3. 本身带参数的装饰器
    4. 类装饰器
    5. 装饰器缺点
    6. 装饰器用途

    闭包

    说到装饰器就不能忽略闭包,下面先介绍一下闭包的概念:

    在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。—— 维基百科 

    简单来说,就是函数内部套函数,里面的函数用到了外面函数的变量,然后把里面的函数当作对象返回,比如下面的例子:

    def Outer(msg):
        def Iner():
            print msg  # msg是外部函数的变量(外部变量)
        return printer  # 返回的是函数,同时延长了外部变量的生命周期
    printer = Outer('test')
    printer()

    上面这个例子展示了基本的闭包,同时闭包也可以下面这样用:

    def adder(x):
        def wrapper(y):
            return x + y
        return wrapper
    
    adder5 = adder(5)
    # 输出 15
    adder5(10)
    # 输出 11
    adder5(6)
    
    

    这时我们避免了使用全局变量,使得外部函数的参数x的生命周期得到延长。

    装饰器

    装饰器其实就是由闭包实现的,下面给出几种不同的装饰器:

    • 最简单的装饰器: 
    def Outer(func):
        def wrapper():
            logging.warn("%s is running" % func.__name__)
            return func()
        return wrapper
    
    @Outer
    def foo():
        print("hello world")
    
    foo()
    • 修饰带参数函数的装饰器:
    def Outer(func):
        def wrapper(*args, **kwargs):
            if level == "warn":
               logging.warn("%s is running" % func.__name__)
            elif level == "info":
               logging.info("%s is running" % func.__name__)
               return func(*args)
            return wrapper
    
        return decorator
    
    @Outer
    def foo(name):
        print("hello world %s" % name)
    
    foo('silly b')
    • 装饰器本身带参数:
    def Outer(level):
        def decorator(func):
            def wrapper(*args, **kwargs):
                if level == "warn":
                    logging.warn("%s is running" % func.__name__)
                elif level == "info":
                    logging.info("%s is running" % func.__name__)
                return func(*args)
            return wrapper
    
        return decorator
    
    @Outer(level="warn")
    def foo(name):
        print("hello world %s" % name)
    
    foo(‘silly b’)
    • 类装饰器:
    class Foo(object):
        def __init__(self, func):
            self._func = func
    
        def __call__(self):
            print ('class decorator runing')
            self._func()
            print ('class decorator ending')
    
    @Foo
    def bar():
        print ('bar')
    
    bar()
    

    使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

    • 类装饰器顺序:
    @a
    @b
    @c
    def f ():
        pass
    
    
    # 调用顺序从下到上,c——b——a:
    f = a(b(c(f)))
    • 装饰器缺点:

    会丢失原函数信息,__docstring__,__name__等都变成wrapper函数的信息了,这时我们需要使用functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的 func 函数中,这使得装饰器里面的 func 函数也有和原函数有一样的元信息了。

    from functools import wraps
    def logged(func):
        @wraps(func)
        def with_logging(*args, **kwargs):
            print func.__name__      # 输出 'f'
            print func.__doc__       # 输出 'does some math'
            return func(*args, **kwargs)
        return with_logging
    
    @logged
    def f(x):
       """does some math"""
       return x + x * x
    • 装饰器一般用途如下:
    1. 注入参数(提供默认参数,生成参数)
    2. 记录函数行为(日志、缓存、计时等功能)
    3. 预处理/后处理(配置上下文)
    4. 修改调用时的上下文(线程异步或者并行,类方法)

    参考文章:

  • 相关阅读:
    jmeter压测,json提取器的使用
    pycharm安装
    安装numpy+mkl
    Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
    windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的解决方式
    mapreduce 设置递归读取输入文件
    设置reduce Task数量
    kafka.common.FailedToSendMessageException: Failed to send messages after 3 tries.
    mahout RecommenderJob 参数含义
    idea 配置日志输出等级debug
  • 原文地址:https://www.cnblogs.com/lizhenghao126/p/11053551.html
Copyright © 2011-2022 走看看