Python中直接使用open()与保存变量的文件读取行为差异问题
问题原因分析与解决方案
这个问题的核心在于文件对象的读取指针行为以及你两次使用文件的方式差异:
1. 第一个print语句的行为
print [ word for word in mywords if all( badchar not in word for badchar in open("badchars.txt").read().split() ) ]
在这个列表推导式里,每处理一个word,你都会重新执行open("badchars.txt").read().split()——相当于每次检查单词时都重新打开一次文件、读取全部内容、分割成["a","b","c"]。
所以当检查"bad"时,badchar中的"b"存在于"bad"里,all(...)返回False,"bad"被排除,最终输出是["good"],符合你的预期。
2. 第二个print语句的问题
with open("badchars.txt") as f: print [ word for word in mywords if all( badchar not in word for badchar in f.read().split() ) ]
这里你只打开了一次文件,得到文件对象f,问题就出在这个文件对象的读取指针上:
- 处理第一个单词"good"时,
f.read()会读取文件全部内容,同时把文件的读取指针移动到文件末尾,split()得到["a","b","c"],检查后"good"符合条件被保留。 - 处理第二个单词"bad"时,你再次调用
f.read(),但此时指针已经在文件末尾了,f.read()会返回空字符串,split()得到空列表[]。而Python里all([])会返回True(因为没有任何元素违反“所有元素都满足条件”的逻辑),所以all(...)错误地返回True,"bad"被保留了下来。
这就是两次输出结果不同的原因!
修复方案
最直接高效的方式是提前读取并保存文件内容到变量,避免重复操作文件对象:
# 先一次性读取所有不良子串并保存 with open("badchars.txt") as f: bad_chars = f.read().split() # 用保存好的变量进行检查 print [ word for word in mywords if all( badchar not in word for badchar in bad_chars ) ]
这样无论检查多少个单词,都只会读取一次文件,而且每次检查都用的是完整的不良子串列表,结果会和第一个print语句一致。
如果你非要复用文件对象(不推荐,没必要),可以在每次读取前用f.seek(0)把指针移回文件开头,但这会额外增加IO操作,不如提前存变量高效。
内容的提问来源于stack exchange,提问作者Heshy
相关产品推荐
相关产品推荐

