V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
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
wenLiangcan
V2EX  ›  Python

用 closure 实现的叠加器(counter)出错,求解释原因

  •  
  •   wenLiangcan · 2014-04-08 23:09:33 +08:00 · 2859 次点击
    这是一个创建于 3972 天前的主题,其中的信息可能已经有所发展或是发生改变。
    (似乎没法分开显示不同的文件。。。)

    看了这篇文章(http://coolshell.cn/articles/10739.html),有一个 Lua 写的 counter,觉得有趣:
    https://gist.github.com/wenLiangcan/10135400#file-counter-lua

    于是学着用 Python 写了一下,可是出错了:
    https://gist.github.com/wenLiangcan/10135400#file-er_counter-py

    搜索后看到这篇文章(http://jjinux.blogspot.com/2006/10/python-modifying-counter-in-closure.html),说把记录计数的变量换做列表就可以了:
    https://gist.github.com/wenLiangcan/10135400#file-counter-py

    请问这是为什么呢?上面文章提到的“to box variables within a closure”又是什么意思?

    function newCounter()
    local i = 0
    return function() -- anonymous function
    i = i + 1
    return i
    end
    end
    c1 = newCounter()
    print(c1()) --> 1
    print(c1()) --> 2
    view raw counter.lua hosted with ❤ by GitHub
    def new_counter():
    i = [0]
    def nested():
    i[0] += 1
    return i[0]
    return nested
    >>>c = new_counter()
    >>>c()
    1
    >>>c()
    2
    view raw counter.py hosted with ❤ by GitHub
    def new_counter():
    i = 0
    def nested():
    i += 1
    return i
    return nested
    c = new_counter()
    c()
    ---------------------------------------------------------------------------
    UnboundLocalError Traceback (most recent call last)
    <ipython-input-3-1f2bdb17cf98> in <module>()
    ----> 1 c()
    <ipython-input-1-6662aa87dc2a> in nested()
    2 i = 0
    3 def nested():
    ----> 4 i += 1
    5 return i
    6 return nested
    UnboundLocalError: local variable 'i' referenced before assignment
    view raw er_counter.py hosted with ❤ by GitHub


    谢谢
    7 条回复    1970-01-01 08:00:00 +08:00
    monsterxx03
        1
    monsterxx03  
       2014-04-08 23:47:00 +08:00   ❤️ 2
    python闭包的经典问题

    i+=1 等价于i = i + 1, 语句从左向右执行,先是`i=`, 注意这里就覆盖了外部的i,实际上外部的i已经不可见了,然后`i+1`, 但此时外部的i在当前作用域中已经不可见,内部的i还未创建完成,等号右边的还没执行完成呢。。。所以会找不到这个i。

    lua能过,应该是语法解释器内部的逻辑和python不一样吧。
    wenLiangcan
        2
    wenLiangcan  
    OP
       2014-04-08 23:58:55 +08:00
    @monsterxx03 那为什么列表又不会被覆盖呢?
    monsterxx03
        3
    monsterxx03  
       2014-04-09 00:04:55 +08:00
    因为 i= xxx是在定义变量, i[0] =xxx 不是定义,只是赋值操作。
    wenLiangcan
        4
    wenLiangcan  
    OP
       2014-04-09 00:22:28 +08:00 via Android
    @monsterxx03 原来如此!
    josephok
        5
    josephok  
       2014-04-12 16:10:23 +08:00
    试试:
    <script src="https://gist.github.com/josephok/10524138.js"></script>
    josephok
        6
    josephok  
       2014-04-12 16:12:08 +08:00   ❤️ 1
    wenLiangcan
        7
    wenLiangcan  
    OP
       2014-04-15 21:31:52 +08:00
    @josephok 原来还有 nonlocal 这个关键字,学习了,v2ex 竟然没有提醒,现在才看到。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1052 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 19:09 · PVG 03:09 · LAX 11:09 · JFK 14:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.