zoukankan      html  css  js  c++  java
  • python 装饰器模式 我的理解

    python和javascript类似, 可以把函数当作函数的返回值, 比如

    def func(f):
        def subfunc():
            print 'subfunc'
        return subfunc
    此外func的参数f也可以是一个函数,正是这样的结构让python可以实现装饰器模式

    def deco(func):
        print("before myfunc() called.")
        func()
        print("  after myfunc() called.")
        return func
     
    def myfunc():
        print(" myfunc() called.")
     
    myfunc = deco(myfunc)
     
    myfunc()
    
    可以看到myfunc被deco包装了一下,在执行前的切面和执行后的切面都增加了一段代码,这就是装饰器的作用.


    在python中还有一个语法糖的概念, 有了它装饰器模式的实现代码可以更加简洁.示意如下:

    def deco(func):
        print("before myfunc() called.")
        func()
        print("after myfunc() called.")
        return func
     
    @deco
    def myfunc():
        print("myfunc() called.")
     
    myfunc()
    myfunc()

    把装饰函数的名字和@符号,放到被装饰函数的上一行,python就会自动开启装饰器模式.

    但是语法糖有一个问题要注意.语法糖对函数的包装只会在编译代码时进行一次.也就是说在编译的时候,python会自动执行:

    myfunc = deco(myfunc)

    所以如果你运行上面这段代码, 编译时会输出:

    before myfunc() called.
    myfunc() called.
    after myfunc() called.

    运行最后两个myfunc()时,又会输出:

    myfunc() called.
    myfunc() called.

    也就是这篇文章第三步中提到的运行结果.正确的方法是定义一个函数,用这个函数作为返回值代替被装饰的函数.

    def deco(func):
        def _deco():
            print("before myfunc() called.")
            func()
            print("after myfunc() called.")
        return _deco
     
    @deco
    def myfunc():
        print(" myfunc() called.")
        return 0
     
    myfunc()
    myfunc()

    一个函数可以被多个装饰函数包装, 比如语法糖的顺序是

    @deco_1
    @deco_2
    def func()
    	pass
    那么装饰的顺序就是:

    func =deco_1(deco_2(func))

    此外装饰器还可以带参数, 在这种情况下装饰函数就会再多一层函数嵌套:

    def deco(arg):
        def _deco(func):
                def wrapper():
                      #begin warpping
                      func()
                      #end warpping
                return wrapper
        return _deco
    
    @deco(1)
    func()
    为什么呢? 因为包装过程是: 
    func = deco(1)(func)
    deco是一个带参数的函数, 而deco(arg)的返回值又是一个以函数为参数的"正常的"装饰函数. 而这个"正常的"装饰函数的返回值又是一个用来代替func()的已经包装好了的函数.


    此外被装饰的函数也可以带参数, 装饰函数的参数还可以是一个类 等等, 我就不一一举例了,大家可以看看这几篇文章:

    http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

    http://www.cnblogs.com/wilber2013/p/4657155.html

  • 相关阅读:
    Ubuntu系统Anaconda安装Pytorch,教你如何优雅的安装环境(1-5)
    优雅的装系统------安装MacOS 10.13.5系统教程
    关闭Ubuntu系统更新方法
    毫秒钟搞定anaconda环境使用清华镜像安装OpenCV,教你如何优雅的安装环境(1-4)
    Ubuntu16.04安装Anaconda3并配置国内镜像,教你优雅的安装环境(1-3)
    Anaconda常用命令
    Ubuntu16.04安装CUDA10.2+cuDNN7.6.5(福利区),教你如何优雅的安装环境(1-2)
    Ubuntu16.04安装NVIDIA驱动,教你如何优雅的安装环境(1-1)
    简述 QPS、TPS、并发用户数、吞吐量关系
    Springboot验证注解@vaild的使用
  • 原文地址:https://www.cnblogs.com/rav009/p/5131060.html
Copyright © 2011-2022 走看看