Python 关于后期绑定的问题,我开始怀疑人生了,求大神解析 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Alerta

Python 关于后期绑定的问题,我开始怀疑人生了,求大神解析

  •  
  •   Alerta Aug 23, 2018 3347 views
    This topic created in 2803 days ago, the information mentioned may be changed or developed.

    当我直接 return 一个匿名函数的时候返回 0,2,4,6

    def testFun(): return(lambda x : i*x for i in range(4)) for everyLambda in testFun(): print(everyLambda(2)) 
    & python test.py 0 2 4 6 

    但是当我把匿名函数作为一个 temp 来返回的时候,结果却是 6,6,6,6

    def testFun(): temp = [lambda x : i*x for i in range(4)] return temp for everyLambda in testFun(): print(everyLambda(2)) 
    & python test.py 6 6 6 6 

    求大神解释解释,这是为什么呀,急求明天就要面试了好紧张

    14 replies    2018-08-27 16:34:47 +08:00
    XiaoxiaoPu
        1
    XiaoxiaoPu  
       Aug 23, 2018
    两段代码的区别不是“把匿名函数作为一个 temp 来返回”,而是第一段代码返回的是生成器,在 for 循环的时候 i 才实际增加,第二段代码返回的是数组,在 for 循环开始的时候 i 已经增加到 3 了
    newmind
        2
    newmind  
       Aug 23, 2018
    第一个是括号(), 为生成器, 返回 generator
    第二个是中括号[], 为列表生成式, 返回数组
    HelloAmadeus
        3
    HelloAmadeus  
       Aug 23, 2018
    ```
    tmp = [lambda x: x*i for i for range(4)]
    ```
    返回的是:
    ```
    tmp = [lambda x: x*3, ...]
    ```
    ```
    tmp = (lambda x: x*i for i for range(4))
    返回的是:
    ```
    tmp = (lambda x: x*0, lambda x: x**1, ...) # 这是一个生成器
    ```

    列表表达式是即时计算的, 而生成器是迭代时才会计算. 返回的 lamda 匿名函数在查找 i 变量的时候, 列表表达式已经算计完了, 此时的 i 值为 3, 所以计算的返回结果是 6, 而在生成器计算的时候, `for i in range(4)` 的计算是惰性的, 只有你去迭代生成器的时候, i 的值才会 +1. 所以 lambda 表达式查找的 i 变量是 0, 1, 2, 3 的序列.
    lixm
        4
    lixm  
       Aug 23, 2018   1
    ```python
    from dis import dis

    f1 = next((lambda x : i*x for i in range(4)))
    dis(f1)
    f2 = [lambda x : i*x for i in range(4)][0]
    dis(f2)
    ```
    都取第 0 个函数出来, 反编译一下就知道, 这两个唯一的区别就是 i,

    f1 是 LOAD_DEREF i 作为闭包传入
    f2 是 LOAD_GLOBAL i 作为全局变量传入

    ```python
    print(f1.func_closure[0].cell_contents)
    ```
    可以看出 作为闭包传入的 i 的值为 0

    ```python
    print(f2.func_globals['i'])
    ```
    可以看出 作为全局变量传入的 i 的值为 3

    为什么会这样呢?因为 Python 里,一切都是引用, 在第一个例子里, 因为生成器是惰性求值, 你可以理解在执行 next, 或者 for 循环的时候, 才求出 i 的值, 所以 i 的值从 0 递增到 3。 在第二个例子里, 列表并不是惰性求值,i 作为一个引用, 值已经变为 3 了

    可能说的不是很清楚, 抱歉
    lolizeppelin
        5
    lolizeppelin  
       Aug 23, 2018 via iPad
    这不是 python 的问题。 我所知的语言里只有 erlang 不出这个问题
    js 之类的一鸟样
    cyrbuzz
        6
    cyrbuzz  
       Aug 24, 2018
    我比较好奇有什么情况下会用这样的写法。
    ipwx
        7
    ipwx  
       Aug 24, 2018
    你需要这么写

    https://ideone.com/mrZkgF
    whoami9894
        8
    whoami9894  
       Aug 24, 2018 via Android
    补充一下,python 中只有 def,class,lambda 会产生作用域,所以这里 for 循环结束后 i 依然存在为 4,这里方括号列表解析生成的 lambda 可以看作是宏,所以会得到 6666 的结果
    josephshen
        9
    josephshen  
       Aug 26, 2018 via iPhone
    我告诉你上面的解释是出现了显现给的解释,原因根源是 python 这门语言的设计问题,导致了分不清申明和赋值
    josephshen
        10
    josephshen  
       Aug 26, 2018 via iPhone
    显示->现象
    Alerta
        11
    Alerta  
    OP
       Aug 26, 2018
    @HelloAmadeus 感谢感谢 一下子明白了
    Alerta
        12
    Alerta  
    OP
       Aug 26, 2018
    @lixm 感激,虽然一开始不是很懂 但是很欣赏你的思考方式,从最根源的现象去推导原因,学习了
    Alerta
        13
    Alerta  
    OP
       Aug 26, 2018
    @cyrbuzz 一个是为了应对面试,二来只是自己无聊刷刷奇怪的题目而已。。。
    U87
        14
    U87  
       Aug 27, 2018
    @lixm 真的 6, 反向思考...赞一下
    About     Help     Advertise     Blog     API     FAQ     Solana     6021 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 59ms UTC 06:32 PVG 14:32 LAX 23:32 JFK 02:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86