我有以下代码片段
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对于我自己更好地理解[]和()与所涉及的迭代器之间的区别非常有用。
答案 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()
非常慢,因此可能有更好的方法。