Python的闭包和装饰器

Python的闭包和装饰器

闭包

闭包(closure)是函数式编程的重要的语法结构,Python也支持这一特性,下面就开始介绍Python中的闭包。

首先看看闭包的概念:闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,闭包是由函数和与其相关的引用环境组合而成的实体。

python函数作用域LEGB

不论在什么语言中,变量都是必不可少的,在python中,一般存在以下几个变量类型,local:函数内部作用域;enclosing:函数内部与内嵌函数之间;global:全局作用域;build-in:内置作用域。解释器在遇到变量的时候,会按照如下的顺序进行查找:L > E > G > B,简称LEGB。

Python中通过提供 namespace 来实现重名函数/方法、变量等信息的识别,其一共有三种 namespace,分别为:

local namespace: 作用范围为当前函数或者类方法

global namespace: 作用范围为当前模块

build-in namespace: 作用范围为所有模块

当函数/方法、变量等信息发生重名时,Python会按照 “local namespace -> global namespace -> build-in namespace”的顺序搜索用户所需元素,并且以第一个找到此元素的 namespace 为准。

简单闭包例子,打招呼:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/7/26 20:38
# @File    : Test4.py
"""
闭包的使用
"""

def outer(greet):
    def inner(name):
        print(greet,name)

    return inner

out = outer('你好')
out('小明')
再看:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/7/26 20:38
# @File    : Test4.py
"""
闭包的使用
"""

def outer(greet):
    def inner(name):
        print(greet,name)

    return inner

out = outer('你好')
print (dir(out))
print (out.__closure__)
print (type(out.__closure__[0]))
print (out.__closure__[0].cell_contents)
输出:
E:\Python3\python.exe E:/Python工作空间/model/close/Test4.py
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
(<cell at 0x00000218DF1055E8: str object at 0x00000218DF100DF0>,)
<class 'cell'>
你好

Process finished with exit code 0

从这里可以看到闭包的原理,当内嵌函数引用了包含它的函数(enclosing function)中的变量后,这些变量会被保存在enclosing function的__closure__属性中,成为enclosing function本身的一部分;也就是说,这些变量的生命周期会和enclosing function一样。

Python中怎么创建闭包

在Python中创建一个闭包可以归结为以下三点:
闭包函数必须有内嵌函数
内嵌函数需要引用该嵌套函数上一级namespace中的变量
闭包函数必须返回内嵌函数
通过这三点,就可以创建一个闭包,是不是想到了上一篇中介绍的Python装饰器。没错,Python装饰器就是使用了闭包。

装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能
简单装饰器:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/7/26 16:17
# @File    : Mydemo1.py

"""
简单装饰器
"""

import time

def func(func):
    def say():
        print('AOP')
        func()
    return say


@func
def Target():
    print('start')
    time.sleep(1)
    print('end')

Target()
通过@语法糖把func函数进行嵌入
再看带参数的的函数:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/7/26 16:42
# @File    : Mydemo2.py

"""
装饰器检验奇数偶数
"""

def check(func):
    def wrapper(a,b):
        res=func(a,b)
        if res % 2 == 0:
            print('偶数')
        else:
            print('奇数')

    return  wrapper

@check
def func(a,b):
    res = a+b
    return  res


func(1,2)
check函数进行奇数偶数校验
从例子中可以看到,对于被装饰函数需要支持参数的情况,我们只要使装饰器的内嵌函数支持同样的签名即可。

带参数的装饰器

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2017/7/26 19:51
# @File    : Mydemo3.py

"""
带参数的装饰器
"""

def check(flag=True):
    if flag:
        def _check(func):
            def wrapper(*args,**kwargs):
                res = func(*args,**kwargs)
                if res % 2 == 0:
                    print('偶数')
                else:
                    print('奇数')

            return  wrapper

    else:

        def _check(func):
            return  func
    return _check

@check(True)
def func1(a,b):
    print('执行func1')
    return a+b


@check(False)
def func2(a,b):
    print('执行func2')
    return a+b

func1(9,10)
func2(9,10)
对func1进行检验,func2则不检验
通过例子可以看到,如果装饰器本身需要支持参数,那么装饰器就需要多一层的内嵌函数
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值