美文网首页
[python]返回函数和装饰器

[python]返回函数和装饰器

作者: 喵吉呀呀 | 来源:发表于2019-04-08 14:56 被阅读0次
    返回函数

    返回函数: 函数作为结果返回
    e.g:

    def lazy_sum(*args):
        def sum():
            ax = 0
            for n in args:
                ax = ax + n
            return ax
        return sum
    
    f = lazy_sum(1,2)   # 调用lazy_sum并传参,实质是把sum赋值给f
    f()  # 调用
    #  这两行相当于lazy_sum(1,2)()
    3
    

    >每次调用都会返回一个新的函数,即使传入相同的参数:

    f1 = lazy_sum(1, 3, 5, 7, 9)
    f2 = lazy_sum(1, 3, 5, 7, 9)
    f1==f2
    >>>False
    
    装饰器(decorator)

    补充知识:
    函数对象有一个name属性
    e.g:

    def now():
        print('2015-3-25')
    f = now
    now.__name__
    >>>'now'
    f.__name__
    >>>'now'
    

    装饰器写法:
    @funcName
    e.g:

    def print_caller(func):
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    def test():
        print('test')
    
    @print_caller
    test()
    
    >>>call test():
    >>>test
    

    decorator实质是返回一个函数,所以,原来的test()函数仍然存在,只是现在同名的test变量指向了新的函数,于是调用test()将执行新函数,即在print_caller()函数中返回的wrapper()函数。
    wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
    所以,@print_caller相当于执行了:

    test = print_caller(test)
    

    打印函数执行前后时间的example:

    def metric(func):
        def decorator(*args, **kw):
            print('start:%s' % int(time.time()))
            time.sleep(2)
            r = func(args, **kw)
            print('end:%s' % int(time.time()))
            return r
        return decorator
    
    @metric
    def test(a):
        print('test')
    
    test()
    
    >>>start:1554695731
    >>>test
    >>>end:1554695733
    
    

    上述几个例子都是decorator不需传参数的情况,如果decorator需要传参数,就需要编写一个返回decorator的高阶函数
    e.g:

    def add_text(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print('text:%s' % text)
                r = func(args, **kw)
                return r
            return wrapper
        return decorator
    
    
    @add_text('miao')
    def test(a):
        print('test')
    
    >>>text:miao
    >>>test
    

    实质是三层的嵌套,@add_text相当于执行了:

    test = add_text('miao')(test)
    

    *decorator本质的嵌套返回函数,会导致原型指针发生变化,name等属性也随之发生变化,如上述的name会从test变成wrapper,理论上应该添加一句wrapper.name = func.name,把原型指针指针原函数,但Python存在内置的functools.wraps做了这个处理

    import functools
    
    # 不带参数的装饰器
    def print_caller(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    # 带参数的装饰器
    def add_text(text):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                print('text:%s' % text)
                r = func(args, **kw)
                return r
            return wrapper
        return decorator
    
    

    相关文章

      网友评论

          本文标题:[python]返回函数和装饰器

          本文链接:https://www.haomeiwen.com/subject/auvqiqtx.html