• Python—闭包和装饰器


    闭包

    定义:内部函数对外部函数变量的引用,则将该函数与用到的变量称为闭包。

    闭包必须满足以下三个条件:

    • 必须有一个内嵌函数。
    • 内嵌函数必须引用外部函数中的变量。
    • 外部函数返回值必须是内嵌函数的引用。
    def func(num):
        def func_in(m):
            print num, m     # 结果:10  3
            new_num = num ** m
            return new_num
        return func_in
    
    if __name__ == '__main__':
        ret = func(10)
        res = ret(3)
        print res      # 结果:1000

    说明:func_in指向func_in()函数,return func_in 将函数的引用返回,用ret接收了这个返回值,ret就指向了func_in所指向的函数体,即func_in()函数。最后调用执行ret所指的函数。这就是闭包的整个过程,func_in()函数以及该函数内用到的变量num就称为闭包。简单说就是如果一个内嵌函数访问了外部嵌套函数作用域内的变量,则这个内嵌函数和用到的变量就称为闭包。将内嵌函数的语句和这些语句的执行环境打包在一起后,得到的函数对象称为闭包。

    装饰器

    装饰器是闭包的一种使用场景,在定义装饰器时需要传入一个函数对象,在此函数执行之前或者之后都可以追加其它的操作。

    装饰器本质上是一个返回函数的高阶函数,装饰器接收要增强的函数,然后在装饰器内部进行功能增强。让函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

    使用场景:性能测试,插入日志,事务管理,权限校验...。就好比是一个切面,也就是我们之后学习中会提到的叫面向切面编程(aop)。

    开放封闭原则:开放表现在不改动源码(破坏原本业务逻辑)的同时扩展新的功能。封闭表现在不允许随意去修改源代码。

    def outer(fun):
        def inner():
            print "功能开始前记录日志"
            fun()
            print "功能结束后记录日志"
        return inner
    
    def work():
        print "hello world"
    
    work = outer(work)
    work()      # 结果打印三行,分别是:功能开始前记录日志   hello world   功能结束后记录日志

    无参无返回值的装饰器,示例如下

    def outer(fun):
        def inner():
            print "功能开始前记录日志"
            fun()
            print "功能结束后记录日志"
        return inner
    
    @outer      # @outer 的效果等同于 work = outer(work),此时work变量指向inner()函数,work()即调用inner()函数。
    def work():
        print "hello world"
    
    work()      # 结果打印三行,分别是:功能开始前记录日志   hello world   功能结束后记录日志

    无参有返回值的装饰器,示例如下

    def make_one(fun):
        def wrapper():
            return "===" + fun() + "==="
        return wrapper
    
    def make_two(fun):
        def inner():
            return "---" + fun() + "---"
        return inner
    
    @make_one
    @make_two
    def work():
        return "hello world"
    
    print work()      # 结果:===---hello world---===
    # 首先执行装饰器make_two,即work = make_two(work)。这时work变量指向inner()函数。inner()函数里面的fun()函数指向work()函数。
    # 然后执行装饰器make_one,即work = make_one(work)。这时work变量指向wrapper()函数。wrapper()函数里面的fun()函数指向inner()函数。
    # 最后执行work()的时候,先执行wrapper()函数,运行里面的fun()函数时候,即执行inner()函数,返回"---hello world---"。

    有参有返回值的装饰器,示例如下

    def make_one(fun):
        def wrapper(name, age, sex):
            fun(name, age, sex)
            return "有参有返回值的装饰器,返回值啦"
        return wrapper
    
    @make_one
    def work(name, age, sex):
        print "我叫:%s,年龄:%s,性别:%s" % (name,age,sex)
    
    print work("小刘",27,"")
    # 运行结果:
    # 我叫:小刘,年龄:27,性别:男
    # 有参有返回值的装饰器,返回值啦

    通用装饰器,示例如下

    # 无参数的装饰器
    def make_one(func):
        def wrapper(*args, **kwargs):
            print args, kwargs
            return func(*args, **kwargs)
        return wrapper
    
    @make_one
    def work():
        print "Hello world"
    
    work()
    # 输出结果:
    # ()  {}
    # Hello world
    # 有参数的装饰器
    def make_one(func):
        def wrapper(*args, **kwargs):
            print args, kwargs
            return func(*args, **kwargs)
        return wrapper
    
    @make_one
    def work(name, age, sex):
        print "我叫:%s,年龄:%s,性别:%s" % (name,age,sex)
    
    work("小刘", 27, "")
    # 输出结果:
    # ('xe5xb0x8fxe5x88x98', 27, 'xe7x94xb7') {}
    # 我叫:小刘,年龄:27,性别:男
    # 有参数有返回值的装饰器
    def make_one(func):
        def wrapper(*args, **kwargs):
            print args, kwargs
            res = func(*args, **kwargs)
            return res  # work函数的返回值
        return wrapper
    
    @make_one
    def work(name, age, sex):
        return "我叫:%s,年龄:%s,性别:%s" % (name,age,sex)
    
    res = work("小刘", 27, "")   # 这里work变量指向wrapper()函数,func变量指向被装饰的真正的work()函数。
    print res
    # 运行结果:
    # ('xe5xb0x8fxe5x88x98', 27, 'xe7x94xb7')  {}
    # 我叫:小刘,年龄:27,性别:男

    附加:当我们定义一个函数的时候,其实也可以理解为我们定义了一个函数变量,我们可以将其作为值赋值给一个变量,或者当作一个方法参数传递。Python中函数也是一个对象,并且可以被直接赋值给变量,就可以通过该变量调用该函数。

    参考:https://www.toutiao.com/i6700739314055119367/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1570675241&app=news_article&utm_source=weixin&utm_medium=toutiao_android&req_id=201910101040410100140470382201FC1A&group_id=6700739314055119367

  • 相关阅读:
    浏览器渲染HTML页面步骤
    JavaScript中必记英语单词及含义
    JavaScript中的线程与进程
    成绩转换 题解
    计算球的体积 题解 #define
    计算两点间的距离 题解
    ASCII码排序 题解
    python学习——协程
    python学习——进程
    python学习——锁
  • 原文地址:https://www.cnblogs.com/liuhaidon/p/11646454.html
Copyright © 2020-2023  润新知