寻找惰性化Python数据的指导原则
注:我已根据评论和答案编辑了原始问题 我的问题是,如果将大量Python数据输入到程序中,如何使这些数据变为惰性数据,从而使内存不会溢出 例如,如果一个列表是通过读取一个文件并将每一行或每一行的一部分附加到一个列表中来构建的,那么这个列表是惰性的吗?换言之,是否可以附加一个列表,而该列表是惰性的?是否附加到将整个文件读入内存的列表 我知道如果我想浏览这个列表,我会编写一个生成器函数来保持访问的惰性 引发这一问题的是最近的 如果这些数据来自一个有10M行的数据库表,比如我们的一个MySQL每日水表读取表,我不会使用mysqldb fetchall()命令,因为我不知道如何使数据延迟。相反,我会一次读一行 但是,如果我确实希望该数据的内容作为惰性序列存在内存中,该怎么办?我将如何在Python中实现它 考虑到我没有针对特定问题提供源代码,我要寻找的答案是指向Python文档中某个位置的指针或指向解决此问题的其他位置的指针寻找惰性化Python数据的指导原则,python,lazy-evaluation,Python,Lazy Evaluation,注:我已根据评论和答案编辑了原始问题 我的问题是,如果将大量Python数据输入到程序中,如何使这些数据变为惰性数据,从而使内存不会溢出 例如,如果一个列表是通过读取一个文件并将每一行或每一行的一部分附加到一个列表中来构建的,那么这个列表是惰性的吗?换言之,是否可以附加一个列表,而该列表是惰性的?是否附加到将整个文件读入内存的列表 我知道如果我想浏览这个列表,我会编写一个生成器函数来保持访问的惰性 引发这一问题的是最近的 如果这些数据来自一个有10M行的数据库表,比如我们的一个MySQL每日水表
谢谢。Python中延迟显示序列的机制是 生成器[sic]函数允许您声明一个行为类似于迭代器的函数,即它可以在for循环中使用
Python中懒洋洋地呈现序列的机制是 生成器[sic]函数允许您声明一个行为类似于迭代器的函数,即它可以在for循环中使用
如果您只是想要一些可以迭代的东西,我会研究生成器: 包含大量相关信息
另一个选项是模块,具体取决于文件的类型。如果您只需要一些可以迭代的内容,我会查看生成器: 包含大量相关信息 另一个选项是模块,具体取决于文件的类型。惰性代码的基本思想是,在需要数据之前,代码不会获取数据 例如,假设我正在编写一个复制文本文件的函数。将整个文件读取到内存中,然后写入整个文件,这并不懒惰。使用
.readlines()
方法构建所有输入行的列表也不是懒惰的做法。但如果一次只读一行,然后在读完后再写每一行,那就太懒了
# non-lazy
with open(input_fname) as in_f, open(output_fname, "w") as out_f:
bytes = in_f.read()
out_f.write(bytes)
# also non-lazy
with open(input_fname) as in_f, open(output_fname, "w") as out_f:
lines = in_f.readlines()
for line in lines:
out_f.write(line)
# lazy
with open(input_fname) as in_f, open(output_fname, "w") as out_f:
for line in in_f: # only gets one line at a time
out_f.write(line) # write each line as we get it
为了使代码变得懒惰,Python允许您使用“生成器”。使用yield
语句编写的函数是生成器。对于您的数据库示例,您可以编写一个生成器,从数据库一次生成一行,然后您可以编写如下代码:
def db_rows(database_name):
# code to open the database goes here
# write a loop that reads rows
# inside the loop, use yield on each row
yield row
# code to close the database goes here
for row in db_rows(database_name):
# do something with the row
“惰性”代码的基本思想是,在需要数据之前,代码不会获取数据
例如,假设我正在编写一个复制文本文件的函数。将整个文件读取到内存中,然后写入整个文件,这并不懒惰。使用.readlines()
方法构建所有输入行的列表也不是懒惰的做法。但如果一次只读一行,然后在读完后再写每一行,那就太懒了
# non-lazy
with open(input_fname) as in_f, open(output_fname, "w") as out_f:
bytes = in_f.read()
out_f.write(bytes)
# also non-lazy
with open(input_fname) as in_f, open(output_fname, "w") as out_f:
lines = in_f.readlines()
for line in lines:
out_f.write(line)
# lazy
with open(input_fname) as in_f, open(output_fname, "w") as out_f:
for line in in_f: # only gets one line at a time
out_f.write(line) # write each line as we get it
为了使代码变得懒惰,Python允许您使用“生成器”。使用yield
语句编写的函数是生成器。对于您的数据库示例,您可以编写一个生成器,从数据库一次生成一行,然后您可以编写如下代码:
def db_rows(database_name):
# code to open the database goes here
# write a loop that reads rows
# inside the loop, use yield on each row
yield row
# code to close the database goes here
for row in db_rows(database_name):
# do something with the row
但是,如果我确实希望该数据的内容作为惰性序列存在内存中,该怎么办
下面是创建惰性序列的方法:不存储项目,而是根据请求动态生成项目,但将其隐藏在[]
语法后面。我总是忘记SQLAPI是如何工作的,所以下面应该理解为伪代码
class Table(object):
def __init__(self, db_cursor):
self._cursor = db_cursor
def __getitem__(self, i):
return self._cursor.fetch_row(i)
def __iter__(self):
for i in xrange(len(self)):
yield self[i]
def __len__(self):
return self._cursor.number_of_rows()
这可以在许多情况下使用,其中可以使用列表
,但实际上不存储任何内容。根据需要添加缓存(取决于访问模式)
但是,如果我确实希望该数据的内容作为惰性序列存在内存中,该怎么办
下面是创建惰性序列的方法:不存储项目,而是根据请求动态生成项目,但将其隐藏在[]
语法后面。我总是忘记SQLAPI是如何工作的,所以下面应该理解为伪代码
class Table(object):
def __init__(self, db_cursor):
self._cursor = db_cursor
def __getitem__(self, i):
return self._cursor.fetch_row(i)
def __iter__(self):
for i in xrange(len(self)):
yield self[i]
def __len__(self):
return self._cursor.number_of_rows()
这可以在许多情况下使用,其中可以使用
列表
,但实际上不存储任何内容。根据需要添加缓存(取决于访问模式)。列表几乎与惰性相反。最好的例子是range
和xrange
之间的差异range
创建一个列表,而xrange
使用生成器根据需要惰性地为您提供每个数字
>>> total = 0
>>> for i in range(2**30):
total += i
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
for i in range(2**30):
MemoryError
>>> print total
0
>>> for i in xrange(2**30):
total += i
>>> print total
576460751766552576
您可以轻松制作自己的发电机:
>>> def myrange(n):
i = 0
while i < n:
yield i
i += 1
>>> sum(xrange(10))
45
>>> sum(myrange(10))
45
>>> myrange(10)
<generator object myrange at 0x02A2DDA0>
列表几乎是懒惰的反面。最好的例子是
range
和xrange
之间的差异range
创建一个列表,而xrange
使用生成器根据需要惰性地为您提供每个数字
>>> total = 0
>>> for i in range(2**30):
total += i
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
for i in range(2**30):
MemoryError
>>> print total
0
>>> for i in xrange(2**30):
total += i
>>> print total
576460751766552576
您可以轻松制作自己的发电机:
>>> def myrange(n):
i = 0
while i < n:
yield i
i += 1
>>> sum(xrange(10))
45
>>> sum(myrange(10))
45
>>> myrange(10)
<generator object myrange at 0x02A2DDA0>
我希望将其存储在RAM中,而不会一下子意识到这一点并导致内存溢出。@octopusgrabbus我还添加了一个链接到
linecache
模块,尽管我也不确定这是您想要的…谢谢。linecache参考很有帮助,但不是我想要的。我希望将其存储在RAM中,而不会一下子意识到这一点并导致内存溢出。@octopusgrabbus我还添加了一个指向linecache
模块的链接,尽管我不确信这也是您想要的…谢谢。linecache参考很有帮助,但不完全是我想要的。我目前无法可视化存储数据的示例