zoukankan      html  css  js  c++  java
  • Python 3 函数自由变量的大坑

    Python中函数是一个对象, 和整数,字符串等对象有很多相似之处,例如可以作为其他函数的参数或返回对象, Python中的函数还可以携带自由变量, 两者无疑极大增进了Python的表达力.

    但是Python函数自由变量的内部机制和列表解析或for循环结合使用时却暗藏杀机:

    复制代码
    #---CASE 1
    fs = map(lambda i:(lambda j: i*j),range(6))
    print([f(2) for f in fs])
    
    #---CASE 2
    fs = [lambda j:i*j for i in range(6)]
    print([f(2) for f in fs])
    
    #---CASE 3
    fs = []
    for i in range(6):
        fs.append(lambda j:i*j)
        if i==3:
            break
    print([f(2) for f in fs])
    
    #---CASE 4
    fs = [(lambda i:lambda j:i*j)(i) for i in range(6)]
    print([f(2) for f in fs])
    复制代码

    结果:

    [0, 2, 4, 6, 8, 10]
    [10, 10, 10, 10, 10, 10]
    [6, 6, 6, 6]
    [0, 2, 4, 6, 8, 10]

    可以通过下面这个简单的测试来分析Python函数在执行时是如何确定自由变量的值的:

    复制代码
    i = 1
    def f(j):
        return i*j
    print(f(2)) # ---> 2
    
    i = 2
    print(f(2)) # ---> 4
    
    def g():
        i = 3
        def f(j):
            return i*j
        return f
    f = g()
    print(f(2)) # ---> 6
    
    i = 100
    print(f(2)) # ---> 6
    复制代码

    可见,当 函数f在*定义时*, Python不会记录自由变量'i'对应什么对象, 只会告诉f, 你有一个自由变量, 它的名字叫 'i'.

    接着, 当函数f在*执行时*, Python告诉f:
    (1) 空间上: 你需要在你被*定义时*的外层namespace里面去查找i对应的对象, 假设这个namespace为X.

    (2) 时间上: 是在你*当前运行时*, X 里面的 i 对应的对象. 

    上面那个简单测试中的 i = 2 之后, f(2)随之也返回4也能反映了这一点.

    CASE 2和3 也是如此, fs里面每个函数对应的自由变量i在*定义时*都是循环变量i, 因此*执行时*都是对应循环结束或跳出时i所指对象.

    而 CASE 1和4为什么能如愿发生变化呢?  这是因为函数对应的自由变量i不再是循环变量i, 而是外层lambda函数*执行时*,循环变量i所指对象在其栈上的拷贝,  由于每次调用外层lambda时i所指对象都不相同, 因此每个函数的自由变量也会指向不同的对象.

    最后, 列表解析里面的作用域是一个全新的作用域,  而普通的for循环则有所不同. 例如:

    复制代码
    #---CASE 2
    fs = [lambda j:i*j for i in range(6)]
    print([f(2) for f in fs])
    i = 4
    print([f(2) for f in fs])
    
    #---CASE 3
    fs = []
    for i in range(6):
        fs.append(lambda j:i*j)
    print([f(2) for f in fs])
    i = 4
    print([f(2) for f in fs])
    复制代码

    结果是:

    [10, 10, 10, 10, 10, 10]
    [10, 10, 10, 10, 10, 10]
    [10, 10, 10, 10, 10, 10]
    [8, 8, 8, 8, 8, 8]
  • 相关阅读:
    UVa 1451 Average (斜率优化)
    POJ 1160 Post Office (四边形不等式优化DP)
    HDU 3507 Print Article (斜率DP)
    LightOJ 1427 Substring Frequency (II) (AC自动机)
    UVa 10245 The Closest Pair Problem (分治)
    POJ 1741 Tree (树分治)
    HDU 3487 Play with Chain (Splay)
    POJ 2828 Buy Tickets (线段树)
    HDU 3723 Delta Wave (高精度+calelan数)
    UVa 1625 Color Length (DP)
  • 原文地址:https://www.cnblogs.com/ITdong-1/p/9941877.html
Copyright © 2011-2022 走看看