6

我有以下代码片段

def send(self, queue, fd):
    for line in fd:
        data = line.strip()
        if data:
            queue.write(json.loads(data))

哪个当然工作得很好,但我有时想知道是否有一种“更好”的方式来编写你只在非空白行上操作的构造。

挑战在于这应该使用“fd”读取的迭代特性,并且能够处理 100+ MB 范围内的文件。

更新 - 在您急于获得这个问题的分数时,您忽略了一个导入部分,即内存使用情况。例如表达式:

 non_blank_lines = (line.strip() for line in fd if line.strip())

将整个文件缓冲到内存中,更不用说执行两次 strip() 操作了。这适用于小文件,但当您有 100+MB 的数据(或偶尔 100GB)时会失败。

部分挑战是以下作品,但阅读起来很困难:

for line in ifilter(lambda l: l, imap(lambda l: l.strip(), fd)):
    queue.write(json.loads(line))

寻找魔术师!

最终更新:PEP-289对我自己更好地理解 [] 和 () 与迭代器之间的区别非常有用。

4

2 回答 2

4

编写的代码没有任何问题,它可读且高效。

另一种方法是将其编写为生成器理解:

def send(self, queue, fd):
    non_blank_lines = (line.strip() for line in fd if line.strip())
    for line in non_blank_lines:
        queue.write(json.loads(data))

如果您正在应用可以采用迭代器的函数,这种方法可能是有益的(更简洁):例如 python3 print

non_blank_lines = (line.strip() for line in fd if line.strip())
print(*non_blank_lines, file='foo')

为了消除对 strip() 的多次调用,将生成器理解链接在一起

stripped_lines = (line.strip() for line in fd)
non_blank_lines = (line for line in stripped_lines if line)

请注意,生成器表达式不会对内存产生不利影响,如本pep中所述。

要更深入地了解这种方法和一些性能基准,请查看这组注释

最后请注意,如果您不需要 strip() 的完整行为,则 rstrip() 将优于 strip()。

于 2012-12-03T17:35:18.350 回答
1

根本没有比您的“更好”的方式,它按预期的方式工作,易于阅读等。但是,如果您确实将速度归类为“更好”,则可以肯定地进行一些小调整。

我对 Python 上的这种速度的东西不太熟悉,但这里有一些建议,它们只在某些条件下有效。我希望其他人会想出更好的东西,也许这个答案会对他们有所帮助。

如果文件不包含诸如

       \n

但只有\n, 那么这种方式会明显更快:

def send(self, queue, fd):
    for line in fd:
        if line != '\n':
            queue.write(json.loads(line.strip()))

时间值:

using: strip() :: 1.8722578811916337
using: line != '\n' :: 1.0126976271093881
using: line != '\n' and line != ' \n' :: 1.2862439244170275

但是请注意,这实际上可能会变得更慢,如果文件没有一行\n,我将它与 fd 一起计时["string", "\n", "test string", "\n", "moreeee", "\n", "An other element"]

\n但是,您可能不知道这些线路.strip()是否很慢,因此可能有更多更好的方法。

于 2012-12-03T18:19:46.560 回答