输出的最后一行没有写入文件

时间:2016-01-17 03:52:49

标签: python-3.x file-io

我正在编写一个程序来计算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)

1 个答案:

答案 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对于保持打开文件更敏感吗?这值得研究,但这个答案足够长(并且可能覆盖的比你想要的还多)。