我正在编写一个程序来计算DNA文件中各种长度核苷酸模式出现的频率。我使用的是Python 3.3.3。我的问题与输出到文本文件是不完整的,并且使用print命令不匹配输出。
这是我对该问题的第二次编辑,我希望这可以解决问题。在下面的代码中,如果删除open()行,则IDE的输出是四行,每行一个字母。如果我将该行留在中,外部输出文件有三行,每行一个字母,第四个字符不打印。使用output命令会产生相同的不完整输出文件。
import sys
H = "agtc"
pattern = ""
for x in H:
count = 1
if x == 'a' or x == 'g' or x == 't' or x == 'c':
while count < 5:
pattern = x
count += 1
sys.stdout = open ('C:/Users/Owner/Desktop/tetramers.txt', 'a')
print (pattern)
答案 0 :(得分:1)
单字答案是“缓冲”,解决方案是with
关键字(和/或buffering=1
),但让我引导您完成一个过程帮助计算出这种事情。
我在我的计算机上使用命令行Python解释器运行了您的示例,它没有出现问题(输出文件包含所有四行)。当您编辑问题并提到“输出到IDE”时,我意识到这可能是一个环境差异。我在Python附带的“IDLE”IDE中尝试了相同的代码,我看到了你描述的问题(输出文件只包含三行)。
问题是文件输出,所以我专注于找到文件输出代码:
import sys
H = "agtc"
...
for x in H:
...
if ...:
...
...
sys.stdout = open ('C:/Users/Owner/Desktop/tetramers.txt', 'a')
print (...)
我们可以简化为:
import sys
for x in "agtc":
sys.stdout = open('C:/Users/Owner/Desktop/tetramers.txt', 'a')
print(...)
现在就是这样,更容易看到代码打开文件四次,但从未明确关闭它。
现在,当我第一次看到sys.stdout = ...
时,我对此表示怀疑。重新分配标准输出不是我每天都做的事情,我想知道这是否可能是问题的一部分。我在不更改stdout的情况下尝试open
文件:
for x in "agtc":
f = open('output.txt', 'a')
print(x, file=f)
它提供相同的输出(三行而不是四行),所以我想重新分配stdout不是问题。尽管如此,这仍然是一个不那么复杂的问题,所以我们会在弄清楚的时候保留更简单的代码。
接下来是什么?我想我知道了,但我现在还要保留这一点 - 这个答案是为了演示思考过程并给你一些调试技巧,你可以在将来使用这些技术来确定与文件无关的问题和缓冲区。
您在评论中提到将open()
移动到循环外部会导致文件为空。这是一个有点不对的暗示:每次打开文件应该更慢,但没有不同的输出。
让我们确认:
f = open('output.txt', 'a')
for x in "agtc":
print(x, file=f)
就像你说的那样......没有输出。 (同样,从IDLE运行时没有输出。它从我的命令行Python生成所有四行。)
因此,当open()
在之前发生四次print()
次调用时,没有输出,但当open()
发生之间四个print()
调用有一些输出,但不是全部。听起来像是一个“fencepost”错误。让我们“展开”for
循环:
f = open('output.txt', 'a')
print("a", file=f)
f = open('output.txt', 'a')
print("g", file=f)
f = open('output.txt', 'a')
print("c", file=f)
f = open('output.txt', 'a')
print("t", file=f)
循环在展开时应该表现相同,实际上这个循环产生与以前相同的三行 - print()
在open()
调用之间调用。如果我们确保print()
来电的所有都在open()
次来电之间会发生什么?
f = open('output.txt', 'a')
print("a", file=f)
f = open('output.txt', 'a')
print("g", file=f)
f = open('output.txt', 'a')
print("c", file=f)
f = open('output.txt', 'a')
print("t", file=f)
f = open('output.txt', 'a')
所有四行都在输出中。现在,显然,在open()
之前和之后调用print()
并不是一个有用的最终解决方案,但它是我们可以用来理解我们遇到的一些谜团的有用的踩踏石。让我们回到我们首先打开文件然后循环写入的示例。它之前是空白的,但是如果我们应用print()
似乎在 两个open()
之间似乎有用的新知识会怎样?
f = open('output.txt', 'a')
print("a", file=f)
print("g", file=f)
print("c", file=f)
print("t", file=f)
f = open('output.txt', 'a')
输出所有行。因此,并非每个print()
都需要两次open()
次呼叫。好。但不是那么好,因为很明显,在完成所有工作后调用open()
没有多大意义。完成后关闭文件会更有意义。等一下......
文件对象是否有close()
方法或类似的东西?我们来看看文档。官方Python 3教程的“Reading and Writing Files”部分说:
完成文件后,请调用f.close()将其关闭并释放打开文件占用的所有系统资源。在调用f.close()之后,尝试使用该文件对象将自动失败。
所以是一个close()
方法。我们在代码中尝试一下:
f = open('output.txt', 'a')
print("a", file=f)
print("g", file=f)
print("c", file=f)
print("t", file=f)
f.close()
嘿,看那个。它的工作原理和是有道理的。好多了。
本教程的下一段也非常有趣:
在处理文件对象时,最好使用
with
关键字。这样做的好处是文件在套件完成后正确关闭,即使在途中引发了异常。
如果您刚开始使用,那么这个新关键字现在可能有点混乱 - 没关系,您可以手动清理,直到您做好准备。看起来有点像这样:
with open('output.txt', 'a') as f:
print("a", file=f)
print("g", file=f)
print("c", file=f)
print("t", file=f)
还有一个尚未解决的谜团:为什么没有问题出现在我的命令行Python中?在IDLE中运行的Python对于保持打开文件更敏感吗?这值得研究,但这个答案足够长(并且可能覆盖的比你想要的还多)。