zoukankan      html  css  js  c++  java
  • Python函数——闭包延迟绑定

    前言

    请看下面代码

    def multipliers():
        return [lambda x : i*x for i in range(4)]
    
    print ([m(2) for m in multipliers()] )
    """
    [6, 6, 6, 6]
    """

    为什么输出结果为[6, 6, 6, 6],这段代码相当于

    def multipliers():
        funcs = []
        for i in range(4):
            def bar(x):
                return x*i
            funcs.append(bar)
        return funcs
    print ([m(2) for m in multipliers()] )
    """
    [6, 6, 6, 6]
    """

    解答

    运行代码,解释器碰到了一个列表解析,循环取multipliers()函数中的值,而multipliers()函数返回的是一个列表对象,这个列表中有4个元素,

    每个元素都是一个匿名函数(实际上说是4个匿名函数也不完全准确,其实是4个匿名函数计算后的值,因为后面for i 的循环不光循环了4次,

    同时提还提供了i的变量引用,等待4次循环结束后,i指向一个值i=3,这个时候,匿名函数才开始引用i=3,计算结果。所以就会出现[6,6,6,6],

    因为匿名函数中的i并不是立即引用后面循环中的i值的,而是在运行嵌套函数的时候,才会查找i的值,这个特性也就是延迟绑定

    # 为了便于理解,你可以想象下multipliers内部是这样的(这个是伪代码,并不是准确的):
    
    def multipliers():
        return [lambda x: 3 * x, lambda x: 3 * x, lambda x: 3 * x, lambda x: 3 * x]

    因为Python解释器,遇到lambda(类似于def),只是定义了一个匿名函数对象,并保存在内存中,只有等到调用这个匿名函数的时候,

    才会运行内部的表达式,而for i in range(4) 是另外一个表达式,需等待这个表达式运行结束后,才会开始运行lambda 函数,此时的i 指向3,x指向2

    改进

    def multipliers():
        # 添加了一个默认参数i=i
        return [lambda x, i=i: i*x for i in range(4)]
    print ([m(2) for m in multipliers()] )
    """
    [0, 2, 4, 6]
    """

    相当于

    def multipliers():
        funcs = []
        for i in range(4):
            def bar(x, i=i):
                return x * i
            funcs.append(bar)
        return funcs
    print ([m(2) for m in multipliers()] )
    """
    [0, 2, 4, 6]
    """

    解答

    添加了一个i=i后,就给匿名函数,添加了一个默认参数,而python函数中的默认参数,

    是在python 解释器遇到def(i=i)或lambda 关键字时,就必须初始化默认参数,

    此时for i in range(4),每循环一次,匿名函数的默认参数i,就需要找一次i的引用,

    i=0时,第一个匿名函数的默认参数值就是0,i=1时,第二个匿名函数的默认参数值就是1,以此类推

    # 为了便于理解,你可以想象下multipliers内部是这样的(这个是伪代码只是为了理解):
    
    def multipliers():
        return [lambda x,i=0: i*x, lambda x,i=1: i*x, lambda x,i=2: i*x, lambda x,i=3:i*x i=3]
    # x的引用是2 所以output的结果就是:[0,2,4,6]

    当然你的i=i,也可以改成a=i。

    def multipliers():
        # 添加了一个默认参数a=i
        return [lambda x, a=i: x*a for i in range(4)]
    print ([m(2) for m in multipliers()] )
    """
    [0, 2, 4, 6]
    """

     Python的延迟绑定其实就是只有当运行嵌套函数的时候,才会引用外部变量i,不运行的时候,并不是会去找i的值,这个就是第一个函数,为什么输出的结果是[6,6,6,6]的原因。

  • 相关阅读:
    (原)Lazarus 异构平台下多层架构思路、DataSet转换核心代码
    (学)新版动态表单研发,阶段成果3
    (学) 如何将 Oracle 序列 重置 清零 How to reset an Oracle sequence
    (学)XtraReport WebService Print 报错
    (原)三星 i6410 刷机 短信 无法 保存 解决 办法
    (原) Devexpress 汉化包 制作工具、测试程序
    linux下网络配置
    apache自带ab.exe小工具使用小结
    Yii::app()用法小结
    PDO使用小结
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/8727474.html
Copyright © 2011-2022 走看看