美文网首页
装饰器的理解

装饰器的理解

作者: BigBigTang | 来源:发表于2019-03-06 22:47 被阅读0次

    装饰器:
    1.用于装饰其他函数
    2.增强被装饰函数的功能
    装饰器需要接受一个函数对象作为参数,以对其进行增强

    def deco(func):
        def wrapper():
            print "decorate something"
            func()
            print "decorate finish"
        return wrapper
    @deco
    def test_func():
        return "test func"
    test_func()
    
    output:
    decorate something
    test func
    decorate finish
    

    test_func()被装饰之后,运行函数test_func(),会运行装饰器这个函数

    当你在用某个@decorator来修饰某个函数func时,如下所示:

    @decorator
    def func():
        pass
    

    其解释器会解释成下面这样的语句:

    func = decorator(func)
    

    先看一个简单的装饰器如下:

    def hello(fn):
        def wrapper():
            print "hello, %s" % fn.__name__
            fn()
            print "goodby, %s" % fn.__name__
        return wrapper
    
    @hello
    def foo():
        print "i am foo"
      
    foo()
    

    输出:

    hello, foo
    i am foo
    goodby, foo
    

    对于一个装饰器的定义:

    @hello
    def foo():
        print "i am foo"
    

    实际上可以理解成foo = hello(foo),将被包装的函数(foo)当作参数传入装饰器(hello)中,通过一系列包装后将包装后的函数再返回给被包装的函数(foo),实际上就是返回了一个新函数,只不过是根据原函数改造而来并且名字不变。

    def out_func(**kwds):
        def real_decorator(fn):
            arg = kwds['arg1'] + kwds['arg2']
            def wapper():
                fn()
                return kwds['arg1'] + kwds['arg2'] + arg
            return wapper
        return real_decorator
    
    @out_func(arg1='11111', arg2='22222')
    def hello_world():
        print('hello world')
    
    print(hello_world())
    

    分析:我的理解是装饰器有两层,内层wapper用于包装,外层decorator(real_decorator)用于接收被包装的函数(hello_world)作为参数,并将包装后的函数(wapper)返回给外部。此处的例子有三层,外层还有一个out_func函数的用处是给内层传递参数,由于外部多了一层函数所以装饰器函数(real_decorator)将装饰器本身返回给out_func,于是@out_func就相当于装饰器。

    functools.wraps
    

    我们在使用 Decorator 的过程中,难免会损失一些原本的功能信息。

    def logged(func):
        def with_logging(*args, **kwargs):
            print func.__name__ + " was called"
            return func(*args, **kwargs)
        return with_logging
    
    @logged
    def f(x):
       """does some math"""
       return x + x * x
    
    def f(x):
        """does some math"""
        return x + x * x
    f = logged(f)
    
    In [24]: f.__name__
    Out[24]: with_logging
    

    由于返回的是包装后的with_logging,所以name等基本信息变成了返回的新函数

    而functools.wraps 则可以将原函数对象的指定属性复制给包装函数对象, 默认有 modulenamedoc,或者通过参数选择。代码如下:

    from functools import wraps
    def logged(func):
        @wraps(func)
        def with_logging(*args, **kwargs):
            print func.__name__ + " was called"
            return func(*args, **kwargs)
        return with_logging
    
    @logged
    def f(x):
       """does some math"""
       return x + x * x
    
    print f.__name__  # prints 'f'
    print f.__doc__   # prints 'does some math'
    
    from functools import wraps
    def logged(func):
        @wraps(func)
        def with_logging(*args, **kwargs):
            print func.__name__ + " was called"
            return func(*args, **kwargs)
        return with_logging
     
    @logged
    def f(x):
       """does some math"""
       return x + x * x
     
    print f.__name__  # prints 'f'
    print f.__doc__   # prints 'does some math'
    

    相关文章

      网友评论

          本文标题:装饰器的理解

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