4

我正在使用 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

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

4

2 回答 2

5

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

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

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

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

(Python 3 改变了这一点,它添加了一个新的关键字nonlocal。如果你定义spamnonlocalinside,bar你可以为该变量分配一个新的值 inside bar。)

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

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

因此,您的“解决方法”是正确的,即使有些晦涩难懂。如果你使用 Python 3,你可以声明chunksnonlocalinside processchunk,然后事情也可以在没有列表的情况下工作。

于 2012-08-24T20:32:42.567 回答
1

在第一种情况下,您正在创建一个名为 的新局部变量chunk。如果您在函数内部分配变量,则变量被视为函数的局部变量。在第二种情况下,您正在修改外部变量引用的列表chunk。因为您没有分配给这个变量,所以它不会被视为本地变量。例如,参见这个先前的问题

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

于 2012-08-24T20:34:26.760 回答