仅处理非空白行

时间:2012-12-03 17:26:06

标签: python

我有以下代码片段

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对于我自己更好地理解[]和()与所涉及的迭代器之间的区别非常有用。

2 个答案:

答案 0 :(得分: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))

如果要应用可以使用迭代器的函数,这种方法可能是有益的(terser):例如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

要更深入地了解这种方法以及一些性能基准测试,请看一下这组notes

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

答案 1 :(得分: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()非常慢,因此可能有更好的方法。