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

    装饰器总结

    前提

    使用装饰器的前提在于Python提供的特性:

    1. 函数即对象,可以进行传递;
    2. 函数可以被定义在另外一个函数中;

    可以通过一个例子来了解:

    def get_animal(name='dog'):
        def dog():
            return 'this is a dog'
        def cat():
            return 'this is a cat'
        # 返回函数对象
        if name == 'dog':
            return dog
        elif name == 'cat':
            return cat
        else:
            return 'other animal'
    animal = get_animal('cat')
    print(animal)  # <function get_animal.<locals>.cat at 0x104b30d90>
    print(animal())
    

    注意:其返回的并不是调用函数,而是返回函数对象,只有在函数对象后面加上括号才表明要进行调用对象。

    装饰器

    装饰器就是可以在原来函数的基础上增加其它的功能,而不改变原函数本身。

    如何写一个装饰器呢,下面给出一个基础的模版:

    def my_decorator(a_function_to_decorate):
        def wapper_function(*args, **kwargs):
            print('Before the function runs')
            a_function_to_decorate(*args, **kwargs)
            print('After the function runs')
        return wapper_function
    @my_decorator
    def stand_function():
        print('stand function runs')
    stand_function()
    

    执行结果为:

    Before the function runsstand function runsAfter the function runs


    如果要求原函数的信息不变,那么可以使用functools.wraps,其本身也是一个装饰器,作用是将原函数的名称、模块、文档字符串等拷贝到装饰器里面的fun函数中,例子如下:

    # "functools" 可以改变这点
    import functools
    def bar(func):
        @functools.wraps(func)
        def wrapper():
            return func()
        return wrapper
    

    需要注意的问题是:

    1. 如果有多个装饰器的时候,则由里到外装饰,也就是按照距离函数的位置谁越近越就被装饰。
    2. 在装饰器的基础上还可以进行装饰,比如装饰装饰器的装饰器。

    如果我们想要使用类来作为装饰器,那么被装饰的函数会作为类的参数被传入到类中。

    比如写一个登陆检查的例子:

    class LoginCheck:
        def __init__(self, f):
            self._f = f
        def __call__(self, *args):
            Status = check_function()
            if Status is True:
                return self._f(*args)
            else:
                return alt_function()
    def check_function():
        return True
    def alt_function():
        return('Sorry - this is the forced behaviour')
    @LoginCheck
    def display_members_page():
        print('This is the members page')
    display_members_page()
    

    过程:它在访问相应的页面的时候,会进行登陆与否的检查,成功则返回相应的信息,反之则提示。


    最后写一个题目,写一个decorator,在函数开始和结束时增加log,并且统计函数执行时间,保留原函数名:

    import logging, time
    def create_logger():
        logger = logging.getLogger("example_logger")
        logger.setLevel(logging.INFO)
        # create the logging file handler
        handler = logging.FileHandler(r"./test.log")
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        # add handler to logger object
        logger.addHandler(handler)
        return logger
    def exception(logger):
        def decorator(func):
            def wrapper(*args, **kwargs):
                start = time.time()
                try:
                    logger.info('function runs')
                    res = func(*args, **kwargs)
                    print('the function used time: {}'.format(time.time()-start))
                    logger.info('function stops')
                    return res
                except:
                    # log the exception
                    err = "There was an exception in  "
                    err += func.__name__
                    logger.exception(err)
                    raise Exception
            return wrapper
        return decorator
    logger = create_logger()
    @exception(logger=logger)
    def foo(name='foo_function'):
        print('i am {}'.format(name))
        return True
    print(foo())
    

    运行结果如下:

    i am foo_functionthe function used time: 0.0008778572082519531True

    logger中的结果如下:

    2017-08-15 03:25:59,234 - example_logger - INFO - function runs2017-08-15 03:25:59,235 - example_logger - INFO - function stops

  • 相关阅读:
    python 进程通信,共享变量
    使用 curl 和 xargs 命令批量删除 ES索引,并将一些不想删除的索引过滤出来
    Spark Over Yarn 发现输出到kafka报错: topic not present on metadata after x
    ES 同台机器多实例报 master not discovered or elected yet
    ES数据写入时间格式问题
    Kibana 发现数据时间不对
    python包部署到服务器上报 cannot find module error
    好久没写博客了,。。。。。
    linux 修改 elf 文件的dynamic linker 和 rpath
    linux 进程 进程组 作业 会话 控制终端
  • 原文地址:https://www.cnblogs.com/George1994/p/7362379.html
Copyright © 2011-2022 走看看