我使用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
我的问题基本上是为什么看起来块/块变量的范围似乎取决于它是普通变量还是列表?
答案 0 :(得分:5)
在python中,如果读取变量,可以从周围的范围“拉出”变量。所以以下内容将起作用:
def foo():
spam = 'eggs'
def bar():
print spam
foo()
因为正在查找周围范围内的变量'spam',foo
函数。
但是,您无法更改周围范围的值。您可以更改全局变量(如果在函数中将它们声明为global
),但在上述函数中不能对变量spam
执行此操作。
(Python 3对此进行了更改,它添加了一个新的关键字nonlocal
。如果您在spam
内定义nonlocal
为bar
,则可以为该变量指定一个新值在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] = ...
)不同。后者正在调用方法来改变列表。