我得到的是其中一个变量的UnboundLocalError
,而不是另一个。
这是让我困惑的代码:
tokens=[]
token_count = 0
def extend():
for word in line.split():
tokens.append(word)
token_count += 1
lines = ['this is one line', 'this is another line']
for line in lines:
extend()
print(tokens)
运行这个你会得到错误:
UnboundLocalError: local variable 'token_count' referenced before assignment
但是删除token_count += 1
行可以使代码运行良好。我知道这可以通过在函数定义后添加global token_count
来解决。
我很难理解为什么Python不抱怨其他变量(例如,for word in line.split()
和tokens
中的line
(。这些变量都是在这个函数之外定义的,如果我为其中一个得到局部变量错误,我也应该为另一个得到它。
对这种行为有什么解释吗?
函数内的变量如果未在函数内赋值,则将从外部作用域继承。但是,如果您在函数内进行赋值,则该变量是局部变量(除非您根据情况使用nonlocal
或global
语句(,并且在赋值之前无法使用其值。在执行token_count += 1
时,您试图在函数内赋值之前查找现有值(以便向其加1(,但这将失败。
利用全局变量通常不是一种好的做法;更好的解决方法是返回一个值。例如:
def extend(tokens, line, token_count):
"extend tokens by the words in line; also return new token count"
for word in line.split():
tokens.append(word)
token_count += 1
return token_count
lines = ['this is one line', 'this is another line']
for line in lines:
token_count = extend(tokens, line, token_count)
print(tokens)
此函数不使用从外部范围继承的变量;所有内容都是函数或函数参数的局部内容。
在token_count
的情况下,它是一个参数,但您正在函数中重新分配它。这很好,但请注意,它不会更改主程序中token_count
的值。稍后将其分配给主程序中的返回值(请参见token_count = extend(...)
行(。
在tokens
的情况下,您通过调用现有可变对象(列表(的append
方法而不是重新分配它(您不是在执行tokens = ...
(来对其进行更改。更新后的值在主程序中也可见。
请注意,在这里,函数既修改可变参数(tokens
(,又返回一个值。这有点不寻常,所以为了避免任何混淆,最好明确声明这就是它正在做的事情——因此在函数开始时使用docstring。
如果您需要以这种方式返回多个值,那么将它们打包到一个元组中,您可以在主程序中对其进行解压缩。
注意:在这种情况下,token_count
的值可以简单地使用len(tokens)
获得,而不是有一个单独的变量,但为了举例,代码没有利用这一事实