Python编程提高:关于闭包和装饰器

2018-10-3109:19:10编程语言入门到精通Comments2,334 views字数 1679阅读模式

闭包

闭包是指在一个函数中定义了一个另外一个函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用,这样就构成一个闭包。 例如以下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

def callFunc():
    n = 1
    def show():
        print('show: ', n)
    return show

s = callFunc()
s()复制代码

去掉了全局变量的使用。而且将 show 函数封装在了 callFunc 函数内部,使外部不可见,不能使用 show 函数,隐藏了实现细节文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

程序在执行时,callFunc 函数返回了内部定义的 show 函数,并且 在 show 函数内部使用了外部函数的变量。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

在 show 函数返回时,保存了当前的执行环境,也就是会在 show 函数中使用的外部变量 n 。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

因为 n 是一个 callFunc 函数中的局部变量,正常情况下 callFunc 函数执行结束后,n 就会被释放。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

但是现在因为 callFunc 函数中返回了 show 函数,show 函数在外部还会再执行,所以程序会将 show 函数所需的执行环境保存下来。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

这种形式就是闭包。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

装饰器

装饰器本身也是一个函数 ,作用是为现有存在的函数,在不改变函数的基础上去增加一些功能进行装饰。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

装饰器实际上就是一个函数 ,这个函数以闭包的形式定义使用 @装饰器函数名 形式来装饰。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

比如现在一个项目中,有很多函数 ,由于项目越来越大,功能越来越多,导致程序越来越慢。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

其中一个功能函数功能,实现一百万次的累加。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

def my_count():
    s = 0
    for i in range(1000001):
        s += i
    print('sum : ', s)复制代码

现在想计算一下函数的运行时间,如何解决?如何能应用到所有函数上?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

解决办法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

import time

def count_time(func):
    def wrapper():      #wrapper 装饰
        start = time.time()
        func()
        end = time.time()
        print('共计执行:%s 秒'%(end - start)) # 使用%d显示,取整后是0秒,因为不到一秒
    return wrapper

@count_time     # 这实际就相当于解决方法3中的 my_count = count_tiem(my_count)
def my_count():
    s = 0
    for i in range(10000001):
        s += i
    print('sum : ', s)

my_count()复制代码

这样实现的好处是,定义好了闭包函数后。只需要通过 @xxx 形式的装饰器语法,将 @xxx 加到要装饰的函数前即可。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

万能装饰器

 def setFunc(func):
        def wrapper(*args, **kwargs):   # 接收不同的参数
            print('wrapper context')
            return func(*args, *kwargs) # 再原样传回给被装饰的函数

        return wrapper

    @setFunc
    def show(name, age):
        print(name,age)

    show('tom',12)
复制代码

通过可变参数和关键字参数来接收不同的参数类型。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

类实现装饰形式

通过类的定义也可以实现装饰器形式。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

在类中通过使用 __init__ 和 __call__方法来实现文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

    class Test(object):
        # 通过初始化方法,将要被装饰的函数传进来并记录下来
        def __init__(self, func):
            self.__func = func
        # 重写 __call__ 方法来实现装饰内容
        def __call__(self, *args, **kwargs):
            print('wrapper context')
            self.__func(*args, **kwargs)


    # 实际通过类的魔法方法call来实现
    @Test  # --> show = Test(show) show由原来引用函数,装饰后变成引用Test装饰类的对象
    def show():
        pass


    show()  # 对象调用方法,实际上是调用魔法方法call,实现了装饰器

作者:贾富程
链接:https://juejin.im/post/5bae1fa95188255c3272c8bd
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html

文章源自菜鸟学院-https://www.cainiaoxueyuan.com/ymba/7587.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/ymba/7587.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定