美文网首页
装饰器(二)-装饰器原理

装饰器(二)-装饰器原理

作者: mysimplebook | 来源:发表于2019-12-24 11:40 被阅读0次

下面具体看下装饰器是如何发挥作用的

首先,看装饰器函数outer,该函数接收一个参数func,其实就是接收一个方法名,outer内部又定义一个函数inner,在inner函数中执行func,同时增加了计时功能,outer的返回值为内部函数inner,其实就是一个闭包函数。

然后,再来看一下,在foo上增加@outer,那这是什么意思呢?当python解释器执行到这句话的时候,会去调用、运行outer函数,同时将被装饰的函数名作为参数传入(此时为foo),

>>> def outer(func):

...     #定义一个内嵌的包装函数,给传入的函数加上计时功能的包装

...     print("nowrunning")

...     def inner():

           print("in inner")

...         start = time.clock()

...         func()

...         end =time.clock()

...         print 'used:', end -start

...     #将包装后的函数返回

...     return inner

...

>>> @outer                              #相当于执行了foo=outer(foo)

... def foo():

...     print("in foo()")

...

now running

>>> 

可见在函数上添加装饰器后,第一层函数就会运行。在执行完outer函数的时候,直接把inner函数返回了,同时把它赋值给foo,此时的foo已经不是未加装饰时的foo了,而是指向了outer.inner函数地址。

接下来,在调用foo()的时候,其实调用的是outer.inner函数,那么此时就会执行计时逻辑,同时在outer.inner函数中调用执行原来的foo(),该处的foo就是通过装饰传进来的参数foo。

这样下来,就完成了对foo的装饰。实际上当python解释器执行到@outer时,就开始进行装饰了(运行装饰器函数了)。

根据原函数是否有参数和有返回值,装饰器函数略有不同。分析如下

对带有参数的函数进行装饰

如果原函数有参数,只需闭包函数和原函数持参数个数一致,并且将参数传递给原方法即可,因此闭包函数参数总是写成(*args,**kwargs)。如

import time

def outer(func):

    #定义一个内嵌的包装函数,给传入的函数加上计时功能的包装

    def inner(*args, **kwargs):

        start = time.clock()

        func(*args, **kwargs)

        end = time.clock()

        print('used:', end - start)

    #将包装后的函数返回

    return inner

                   

                   

@outer

def foo(*args, **kwargs):

    print("in foo()")

print('%d  + %d  = %d ' % (args[0], args[1], args[0] +args[1]))

 

      运行foo函数,如

>>> foo(2,3)

in foo()

2  + 3  = 5

('used:', 0.0)

>>> 

可见利用python的可变参数轻松实现装饰带参数的函数。

对带有返回值的函数进行装饰

如果原foo函数有返回值。在inner函数中对foo进行了调用,如果没有用return语句,即没有进行返回,那么默认返回就是None了。

import time

def outer(func):

    #定义一个内嵌的包装函数,给传入的函数加上计时功能的包装

    def inner(*args, **kwargs):

        '''inner decorator'''

        start = time.clock()

        ret = func(*args, **kwargs)

        end = time.clock()

        print('used:', end - start)

        return ret

    #将包装后的函数返回

    return inner

   

@outer

def foo(*args, **kwargs):

    '''docstring'''

    print("in foo()")

    return "hello"+args[0]

       如果闭包函数内没有return语句,原函数将打印“hello

None”。

>>> foo("world")

in foo()

('used:', 0.0)

'hello world'

>>> 

给装饰器传参

       上面看到的装饰器都不能传参,如果要给装饰器传参,需要再在装饰器外部封装一层函数,然后返回这个装饰器,这样装饰器函数可以使用传入的参数了,如在outer函数外面封装一层函数,如

def wrapouter(para):

    def outer(func):

        #定义一个内嵌的包装函数,给传入的函数加上计时功能的包装

        def inner(*args, **kwargs):

            '''inner decorator'''

            print("now runningfunction: "+para)

            start = time.clock()

            ret = func(*args,**kwargs)

            end = time.clock()

            print('used:', end -start)

            return ret

        #将包装后的函数返回

        return inner

    return outer

第一层函数,可以用来接收传递进来的参数;第二层函数,是接收传进来的函数对象。则装饰foo函数示例为

@wrapouter("foo")                                 #首先执行wrapouter(‘foo’) ,再执行@outer

def foo(*args, **kwargs):

    '''docstring'''

    print("in foo()")

    return "hello"+args[0]

       运行测试

>>> foo("world")

now running function: foo

in foo()

('used:', 0.0)

'hello world'

>>> 

相关文章

  • 装饰器(二)-装饰器原理

    下面具体看下装饰器是如何发挥作用的 首先,看装饰器函数outer,该函数接收一个参数func,其实就是接收一个方法...

  • python3基础---详解装饰器

    1、装饰器原理 2、装饰器语法 3、装饰器执行的时间 装饰器在Python解释器执行的时候,就会进行自动装饰,并不...

  • python之装饰器模版

    装饰器的作用:装饰器即可以装饰函数也可以装饰类。装饰器的原理:函数也是对象 1.定义装饰器 2.使用装饰器假设de...

  • Python装饰器

    Python装饰器 一、函数装饰器 1.无参装饰器 示例:日志记录装饰器 2.带参装饰器 示例: 二、类装饰器 示例:

  • Python day30_闭包与装饰器

    闭包 装饰器 装饰器结论: 一个装饰器一个函数了解 二个装饰器装饰一个函数图解大法 二个装饰器装饰器一个函数内存图...

  • Python装饰器的几种类型

    装饰器的原理就是闭包,这在前面已经提到过了。本篇主要记录一下装饰器的几种类型。 无参数装饰器 有参数装饰器 类装饰...

  • python装饰器,生成器,迭代器

    装饰器 运用了闭包的原理通过一个@符号将装饰器置于其要装饰的方法的上方可以多个装饰器装饰同一个方法 装饰器可以用可...

  • 装饰器

    """@装饰器- 普通装饰器- 带参数的装饰器- 通用装饰器- 装饰器装饰类- 内置装饰器- 缓存装饰器- 类实现...

  • typescript 五种装饰器

    装饰器类型 装饰器的类型有:类装饰器、访问器装饰器、属性装饰器、方法装饰器、参数装饰器,但是没有函数装饰器(fun...

  • python 装饰器(类装饰器和函数装饰器)

    一、函数装饰器示例 二、类装饰器

网友评论

      本文标题:装饰器(二)-装饰器原理

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