• python


    百度百科上的定义:

    闭包就是能够读取其他函数内部变量的函数。只有函数内部的子函数才能读取局部变量,所以闭包可以理解成 “定义在一个函数内部的函数” 。
    在本质上,闭包是将函数内部和函数外部连接起来的桥梁。


    举个栗子,例子1

    def sum(a):
        def add(b):
            return a + b
        return add
    
    num = sum(2)
    print(num)
    print(type(num))
    print(num.__name__)  # 打印函数的名称,从结果可以看出,返回函数add
    
    # 运行结果
    <function sum.<locals>.add at 0x0000000001E11048>
    <class 'function'>
    add
    

    解析说明

    如果再一个函数内部嵌套了另外一个函数(将外部的函数和内部的函数成为外函数和内函数),函数中引用了外函数中的变量,并且外函数的返回值是内函数,称之为 闭包。


    上面的列子:
    sum 为外函数,add 为内函数;
    内函数 add 引用了外函数 sum 的变量a;
    外函数 sum 返回内函数 add;
    符合闭包的定义。
    

    普通函数

    一般情况下,函数调用结束后,函数内定义的变量将不可使用。

    # -*- coding:utf-8 -*-
    def do_sth():
        temp = 9
        print(temp)
    
    do_sth()  # 调用函数,打印 temp
    
    print(temp)  # 会报错,提示temp没定义, NameError: name 'temp' is not defined
    

    闭包

    对于闭包而言,外函数调用结束后,外函数中被内函数引用的变量仍然可用,
    因为外函数中被内函数引用的变量会被绑定到内函数的特殊属性__closure__中。

    def outer():
        a = 9
        def inner():
            print(a)
        return inner
    
    outer()() # 9
    

    外函数中被内函数引用的变量会被绑定到内函数的特殊属性__closure__中。

    def outer():
        a = 9
        def inner():
            print(a)
        return inner
    
    result = outer()
    print(result.__closure__)  # (<cell at 0x0000000001DEF978: int object at 0x000007FED6CF7D40>,) 是一个元祖
    print(result.__closure__[0].cell_contents)  # 9
    # closure:闭包
    # cell_contents: 单元格内容
    

    栗子2

    def outer():
        a = 9
        def inner():
            a += 1
        return inner
    
    outer()()
    # UnboundLocalError: local variable 'a' referenced before assignment
    # UnboundLocalError:赋值前引用的局部变量“a”
    
    """
    a += 1 相当于 a = a + 1
    重新定义一个变量 a, 把外函数中的变量 a 给屏蔽了;
    当计算等号右边的 a + 1 时,新定义的变量 a 还没有被赋值,因此程序会报错
    """
    

    栗子3

    def outer():
        a = [5]  # a 为列表,列表是可变类型对象
        def inner():
            a[0] = 9  # 此时 a 没有波浪线了,修改列表 a 的对象的值,把列表的值改为 9
    
            print(a)
        return inner
    
    outer()()  # [9]
    

    对比例2和例3,得出的结论:

    在默认情况下,在内函数中不能修改外函数中的变量引用的对象,
    如果引用的对象是可变类型的,可以修改对象的内容。


    如果想在内函数中修改外函数中的变量所引起的的对象,要怎么办?

    def outer():
        a = 10  # a 为列表,列表是可变类型对象
    
        def inner():
            nonlocal a
            a += 1
    
            print(a)
        return inner
    
    
    outer()()  # 11
    

    如果想在内函数中修改外函数中的变量所引起的的对象,可以在内函数中使用关键字
    nonlocal对变量进行声明,从而表明在内函数中并没有重新定义一个新的同名变量,
    而是使用外函数中该名称的变量。



    闭包经典面试题

    1、下列程序是否是闭包,是否能正常运行

    def outer():
        n = 2
        
        def inner(x):
            n += 1
            return x ** n
        return inner
    
    p = outer()
    print(p(3))
    

    解析:是闭包,但是运行会报错

    修改:

    def outer():
        n = 2
    
        def inner(x):
            nonlocal n
            n += 1
            return x ** n
        return inner
    
    p = outer()
    print(p(3))  # 27
    

    2、以下程序执行的结果是多少

    def outer():
        n = 2
        L = []
        for i in range(1, 3):
            def inner():
                return i ** n
            L.append(inner)
        return L
    
    
    f1, f2 = outer()
    print(f1())  # 4
    print(f2())  # 4
    

    python的函数只有在执行时,才会去找函数体里的变量的值,也就是说你连形参都不确定,
    你咋知道i为几呢?,在这里,你只需要记住如果你连形参都不确定,python就只会记住最后一个i值。



    ------分界线------

    * 学到知识
    * 积累经验
    * 太高思维
    * 锻炼心性 
    * ......
    
    ------
    
    

    有了这个思维,

    你自然会变得更好,
    结果就自然会变好,
    钱自然会来找你,

  • 相关阅读:
    目标检测——Faster R_CNN使用smooth L1作为bbox的回归损失函数原因
    [LeetCode] 2. Add Two Numbers
    XAF 非持久化的详细视图界面全部清空
    4月份开发的问题汇总
    XAF GroupOperator合并查询筛选条件
    C#判断字符判断为空或者空格
    如何去掉C#字符串前后的空格
    IIS 发布出去未能加载文件或程序集“UHFReader”或它的某一个依赖项。试图加载格式不正确
    《图解HTTP》笔记
    Win10中的控制台程序会被鼠标单击暂停运行的解决办法
  • 原文地址:https://www.cnblogs.com/wwho/p/15434783.html
Copyright © 2020-2023  润新知