• python闭包和装饰器(转)


     

    一、python闭包

    1、内嵌函数

    >>> def func1():
    ...     print ('func1 running...')
    ...     def func2():
    ...             print ('func2 running...')
    ...     func2()
    ... 
    >>> func1()
    func1 running...
    func2 running...

    内部函数func2作用域都在外部函数func1作用域之内 
    如果试图在外部函数的外部调用内部函数将会报错

    >>> func2()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'func2' is not defined

    如果试图在一个内部函数里对外部作用域(不包括外部函数的外部作用域)的变量进行引用,内部函数就会被认为是闭包

    >>> def FuncX(x):
    ...     def FuncY(y):
    ...             return x*y
    ...     return FuncY

    对于FuncY函数来说,对在FuncX函数的整个作用域(FuncY函数的非全局作用域的外部作用)的变量x进行引用,自此就可以说FuncY函数就是所谓的闭包

    >>> f = FuncX(8)
    >>> f
    <function FuncY at 0x7f3a436fc2a8>
    >>> type(f)
    <type 'function'>
    >>> f(10)
    80
    >>> FuncX(7)(8)
    56

    由于闭包本身是基于内部函数这一概念而来,所以不能在外部函数的外部作用域对内部函数进行调用

    >>> FuncY(8)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'FuncY' is not defined

    既然是基于内部函数这一概念而来,自然对于内部函数来说对引用外部函数作用域内的变量进行修改,将会启动解释器的屏蔽机制

    >>> def Func1():
    ...     x = 233
    ...     def Func2():
    ...             x *=x
    ...             return x
    ...     return Func2()
    ... 
    >>> Func1()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in Func1
      File "<stdin>", line 4, in Func2
    UnboundLocalError: local variable 'x' referenced before assignment

    x*=x的左值此时是内部函数作用域里的变量,此时试图将没有定义的数据进行平方操作,因此报错

    >>> def Func1():
    ...     x = 233
    ...     def Func2():
    ...             x = 321
    ...             return x
    ...     return Func2()
    ... 
    >>> Func1()
    321

    内部函数创建x变量并且屏蔽外部函数作用域内的x变量

    python3之前的解决办法

    应用容器类型(list,tuple之类的)存放外部函数作用域的变量从而不会被屏蔽机制屏蔽掉,因为容器类型不是存放在栈里面

    >>> def Func1():
    ...     x = [233]
    ...     def Func2():
    ...             x[0] *= x[0]
    ...             return x[0]
    ...     return Func2()
    ... 
    >>> Func1()
    54289

    python3之后的解决办法:nonlocal关键字

    >>> def Func1():
    ...     x = 233
    ...     def Func2():
    ...     nonlocal x
    ...             x *= x
    ...             return x
    ...     return Func2()
    ... 
    >>> Func1()
    54289

    二、装饰器

    事实上,装饰器就是一种的闭包的应用,只不过其传递的是函数:

     @makeitalic 装饰器将函数 hello 传递给函数 makeitalic,函数 makeitalic 执行完毕后返回被包装后的 hello 函数,而这个过程其实就是通过闭包实现的。@makebold 也是如此,只不过其传递的是 @makeitalic 装饰过的 hello 函数,因此最后的执行结果 <b> 在 <i>外层,这个功能如果不用装饰器,其实就是显式的使用闭包:

    闭包的作用

    闭包的最大特点是可以将父函数的变量与内部函数绑定,并返回绑定变量后的函数(也即闭包),此时即便生成闭包的环境(父函数)已经释放,闭包仍然存在,这个过程很像类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活,现举一例:假设我们仅仅想打印出各类动物的叫声,分别以类和闭包来实现:

    可以看到输出结果是完全一样的,但显然类的实现相对繁琐,且这里只是想输出一下动物的叫声,定义一个 Animal 类未免小题大做,而且 voice 函数在执行完毕后,其作用域就已经释放,但 Animal 类及其实例 dog 的相应属性却一直贮存在内存中:

    而这种占用对于实现该功能后,则是没有必要的。

    除此之外,闭包还有很多其他功能,比如用于封装等,另外,闭包有效的减少了函数参数的数目,这对并行计算非常有价值,比如可以让每台电脑负责一个函数,然后串起来,实现流水化的作业等。

    转自:http://blog.csdn.net/ChangerJJLee/article/details/52598629

    https://segmentfault.com/a/1190000004461404

  • 相关阅读:
    转:五年java人的一点感悟
    6:ZigZag Conversion
    5:Longest Palindromic Substring
    4:Median of Two Sorted Arrays
    3:Longest Substring Without Repeating Characters
    读写分离
    docker swarm部署spring cloud服务
    kubeadm方式安装kubernetes
    《Spring Boot 实战》随记
    https部署
  • 原文地址:https://www.cnblogs.com/shixisheng/p/7093800.html
Copyright © 2020-2023  润新知