python yield生成器变量范围

时间:2012-08-24 20:23:34

标签: python regex scope generator yield

我使用yield来创建一个生成器,该生成器返回使用正则表达式和re.sub()提取的字符串的块。虽然我发现了一种有效的方法,但我对它为什么会以某种方式工作而不是另一种方式感到有点困惑,如下所示:

这不起作用(processchunk()没有分配给splitmsg中声明的块):

def splitmsg(msg):
    chunk = None
    def processchunk(match):
        chunk = match.group(1)
        return ""
    while True:
        chunk = None
        msg = re.sub(reCHUNK,processchunk,msg,1)
        if chunk:
            yield chunk
        else:
            break     

这确实有效(注意唯一不同的是块现在是列表块):

def splitmsg(msg):
    chunks = [ None, ]
    def processchunk(match):
        chunks[0] = match.group(1)
        return ""
    while True:
        chunks[0] = None
        msg = re.sub(reCHUNK,processchunk,msg,1)
        if chunks[0]:
            yield chunks[0]
        else:
            break

我的问题基本上是为什么看起来块/块变量的范围似乎取决于它是普通变量还是列表?

2 个答案:

答案 0 :(得分:5)

在python中,如果读取变量,可以从周围的范围“拉出”变量。所以以下内容将起作用:

def foo():
    spam = 'eggs'
    def bar():
        print spam
foo()

因为正在查找周围范围内的变量'spam',foo函数。

但是,您无法更改周围范围的值。您可以更改全局变量(如果在函数中将它们声明为global),但在上述函数中不能对变量spam执行此操作。

(Python 3对此进行了更改,它添加了一个新的关键字nonlocal。如果您在spam内定义nonlocalbar,则可以为该变量指定一个新值在bar内。)

现在到你的清单。那里发生的是你根本没有改变变量chunks。在整个代码中,chunks指向一个列表,并且仅指向该列表。就python而言,chunks变量在processchunk函数中不会改变。

发生的是您更改列表的内容。您可以自由地为chunks[0]分配一个新值,因为它不是变量chunks,而是第一个索引chunks引用的列表。 Python允许这样做,因为它不是变量赋值,而是列表操作。

所以,你的'解决方法'是正确的,如果有点模糊。如果您使用Python 3,则可以在chunks中将nonlocal声明为processchunk,然后在没有列表的情况下也能正常工作。

答案 1 :(得分:1)

在第一种情况下,您正在创建一个名为chunk的新局部变量。如果在函数内部赋值变量,则将变量视为函数的局部变量。在第二种情况下,您正在修改外部变量chunk引用的列表。因为您没有分配给此变量,所以不会将其视为本地变量。例如,请参阅this previous question

在Python中分配一个裸名称(someName = ...)与其他任何东西都不一样;特别是它与项目分配(someName[0] = ...)不同。后者正在调用方法来改变列表。