读取文件并通过分隔符分隔行的最佳方法是什么。 返回的数据应该是元组列表。
这种方法可以被打败吗?这可以更快/使用更少的内存吗?
def readfile(filepath, delim):
with open(filepath, 'r') as f:
return [tuple(line.split(delim)) for line in f]
答案 0 :(得分:14)
您发布的代码读取整个文件并在内存中构建该文件的副本,作为分成元组的所有文件内容的单个列表,每行一个元组。由于您询问如何使用更少的内存,您可能只需要一个生成器函数:
def readfile(filepath, delim):
with open(filepath, 'r') as f:
for line in f:
yield tuple(line.split(delim))
BUT!有一个重要的警告!您只能迭代readfile返回的元组一次。
lines_as_tuples = readfile(mydata,','):
for linedata in lines_as_tuples:
# do something
到目前为止这没关系,生成器和列表看起来一样。但是,假设您的文件包含大量浮点数,并且您在文件中的迭代计算了这些数字的总体平均值。您可以使用“#do something”代码来计算总数和数字,然后计算平均值。但现在让我们说你想再次迭代,这次是为了找出每个值的平均值的差异。你认为你只需添加另一个for循环:
for linedata in lines_as_tuples:
# do another thing
# BUT - this loop never does anything because lines_as_tuples has been consumed!
BAM!这是生成器和列表之间的巨大差异。现在在代码的这一点上,生成器已被完全消耗 - 但没有引发特殊异常,for循环什么都不做,继续,静默!
在许多情况下,您将获得的列表仅迭代一次,在这种情况下,将readfile转换为生成器就可以了。但是如果你想要的是一个更持久的列表,你将多次访问它,那么只使用一个生成器会给你带来问题,因为你只能迭代生成器一次。
我的建议?使readlines成为一个生成器,这样在它自己的世界观点中,它只会产生文件的每个增量位,既美观又节省内存。将保留数据的负担放在调用者身上 - 如果调用者需要多次引用返回的数据,则调用者可以简单地从生成器构建自己的列表 - 使用list(readfile('file.dat', ','))
在Python中轻松完成。 / p>
答案 1 :(得分:3)
使用生成器而不是列表和列表而不是元组可以减少内存使用,因此您不需要立即将整个文件读入内存:
def readfile(path, delim):
return (ln.split(delim) for ln in open(f, 'r'))
但是,您必须依赖垃圾收集器来关闭文件。至于返回元组:如果没有必要就不要这样做,因为列表的速度要快一点,构造元组的成本很小,而且(重要的是)你的线将被分成可变大小的序列,这些是概念列表。
我想,只有降低到C / Cython水平才能提高速度; str.split
很难被击败,因为它是用C语言编写的,而列表推导是AFAIK是Python中最快的循环结构。
更重要的是,这是非常清晰的Pythonic代码。除了发电机位之外,我不会尝试优化它。