zoukankan      html  css  js  c++  java
  • python的闭包

    *从作用域的概念开始:

    全局作用域:整个程序运行环境中都可见。

    局部作用:函数、类内部可见。

    两者特点:

    1.局部变量使用范围不能超过其所在的局部作用域。

    2.外层变量作用域在内层作用域可见。在内层作用域定义一个同名的局部变量时,相当于在当前作用域重新定义一个新的变量,但不会覆盖外层作用域的同名变量。举例如下:

    x = 5
    def foo():
        y = x + 1
        print(y)
    
    foo()

     输出的结果是6;因为在foo()函数内引用到外部作用域的x变量。

    x = 5
    def foo():
        x += 1
        print(x)
    
    foo()

    这时候会报错:local variable 'x' referenced before assignment。为什么呢?因为x += 1等价于 x = x + 1,相当于在foo()函数内部重新定义一个局部变量x,那么foo()函数内部所有x都是这个局部变量x,但这个x还没有完成赋值,就被进行加1操作。

    (python动态语言中赋值才算定义,才能被引用。这里x没有赋值就无法被引用)

    解决办法:

    x = 5
    def foo():
        global x
        x += 1
        print(x)
    
    foo()

     global将foo内的x声明为使用外部的全局作用域中定义的x。此时就会成功输出6。那么如果foo外部没有x变量的声明,是否还会报错呢?

    def foo():
        global x
        x = 10
        x += 1
        print(x)
    
    foo()

     此时会成功输出11。说明:一旦作用域中使用global关键字声明为全局的,那么x=10相当于在为全局作用域的变量x赋值。

    *关键字global

    1.使用global关键字的变量,将会被声明为外部的全局作用域中定义的变量

    2.外部作用域的变量会在内部作用域中可见,但是也不要在内部的局部作用域中直接使用,因为函数的目的是为了封装,尽量与外界隔离。

    3.如果函数需要使用外部全局变量,使用函数的形参传参解决。

    *闭包概念

    自由变量:未在本地作用域(非全局作用域!)中定义的变量。例如:定义在内层函数外的外层函数的作用域中的变量。

    闭包:内层函数引用到外层函数的自由变量。(最常见的就是JavaScript)

     python2中实现闭包的举例如下:

    def counter():
        c = [0]
        def inc():
            c[0] += 1
            return c[0]
           return inc

    foo = counter()
    print(foo(), foo()) # 打印1 2

    c = 100
    print(foo()) # 打印3

     此时c[0] += 1并不会像上面的x += 1情况报错。为什么呢?因为c已经在外层函数counter()里定义过,内层函数inc()里并不是对c的重新定义,而是对列表c内的元素进行修改。

    c=100中的c和counter()中的c不一样,inc()引用的是自由变量,正是counter()中的变量c。

    上面的例子是针对dict,list这些可变对象的闭包,但是对于int,string,float,tuple这些python中不可变对象变量的闭包,python3里可以使用nonlocal实现。

    nonlocal:使用nonlocal关键字,将变量标记为上级的局部作用域中定义,但不能是全局作用域中定义的变量。

    def counter():
        count = 0
        def inc():
            nonlocal count
            count += 1
            return count
        return inc
    
    foo = counter()
    print(foo())  # 1
    print(foo()) # 2

     该例子就是一个正常使用的闭包。

    a = 10
    def counter():
        nonlocal a
        a += 1
        print(a)
    
        count = 0
        def inc():
            nonlocal count
            count += 1
            return count
    
        return inc
    
    foo = counter()
    foo()
    foo()    

    nonlocal a中a的上一级作用域是全局作用域,所以代码不能正常运行。

  • 相关阅读:
    Linux学习记录(四):Shell脚本
    Linux学习记录(三):Vim
    基于PyTorch构建神经网络
    Python开发【第一篇】:初识Python
    asyncio 并发编程(二)
    asyncio 并发编程(一)
    Linux 文件和目录操作命令(一)
    Django Model
    Django 之 Form 组件
    Django 模板系统
  • 原文地址:https://www.cnblogs.com/hongdanni/p/10458568.html
Copyright © 2011-2022 走看看