Python函数变量与参数作用域疑问及test1/test2输出差异解惑
问题解析:Python函数默认参数的求值时机与迭代器特性
嘿,我来帮你拆解这个问题——你遇到的核心坑其实是Python里默认参数的求值时机,再加上文件对象作为迭代器的特性,才导致了test1和test2看起来逻辑一致却输出不同的结果。
先搞懂两个关键知识点
- Python默认参数的求值时机:函数的默认参数是在函数定义的时候就计算好了,而不是你调用函数的时候。很多新手都会误以为默认参数是每次调用时才生成,这是个常见误区。
- 文件对象是一次性迭代器:用
open()打开的文件对象属于迭代器,它的内容只能被遍历一次。当你把文件里的内容读完一遍后,迭代器就走到了末尾,再去遍历它就不会返回任何内容了。
结合你的代码一步步分析
来看你的代码执行流程:
- 首先执行
fin=open('D:\\Python\\Think Python\\words.txt'),打开文件得到一个文件对象fin。 - 接下来定义
test1函数:它的默认参数worklist1=build_list_append(fin)会立刻执行——也就是调用build_list_append(fin),遍历fin里的所有行,把单词都加到列表里返回,此时worklist1就是这个非空列表。同时,fin这个迭代器已经被遍历完了,内部指针移到了文件末尾。 - 然后定义
test2函数:它的默认参数worklist2=build_list_append(fin)也会立刻执行,但这时候fin已经没有内容可以遍历了(因为刚才被test1的默认参数调用读完了),所以build_list_append返回的是空列表,worklist2就是空的。
所以当你调用test1()的时候,用的是定义时就生成的非空列表;调用test2()的时候,用的是定义时生成的空列表——这就是两者输出不同的原因。
关于作用域的补充
你提到的变量与参数的作用域问题,这里需要明确:函数默认参数的求值是在全局作用域里完成的(因为函数定义在全局环境),所以build_list_append(fin)里的fin是全局变量里的那个文件对象,而不是函数内部的局部变量。
如果想要避免这种问题,通常的做法是把默认参数设为None,然后在函数内部再初始化,比如:
fin=open('D:\\Python\\Think Python\\words.txt') def build_list_append(file): word_list=[] for line in file: word=line.strip() word_list.append(word) return word_list # 修改后的test1和test2 def test1(worklist1=None): if worklist1 is None: fin.seek(0) # 把文件指针移回开头 worklist1=build_list_append(fin) print("This is test1,It will return a non-empty list") print(len(worklist1)) def test2(worklist2=None): if worklist2 is None: fin.seek(0) worklist2=build_list_append(fin) print("This is test2,It will return a non-empty list now") print(len(worklist2))
这样修改后,每次调用test1或test2时,如果没有传入参数,都会把文件指针移回开头,重新读取内容,两者就会返回相同的非空列表长度了。
内容的提问来源于stack exchange,提问作者XQ_CHIA
相关产品推荐
相关产品推荐

