注意:我根据评论和答案编辑了原始问题。
我的问题是,如果将大量Python数据输入到程序中,该数据如何变得懒惰,因此内存不会溢出?
例如,如果通过读入文件并将每行或每行的一部分附加到列表来构建列表,那么该列表是否是惰性的?换句话说,是否可以附加列表并且列表是懒惰的?是否附加到将整个文件读入内存的列表中?
据我所知,如果我想浏览该列表,我会编写一个生成器函数来保持访问权限。
触发这个问题的是最近的SO post
如果这些数据来自一个包含10M行的数据库表,就像我们的MySQL日常水表读取表一样,我不会在不知道如何使数据变得懒惰的情况下使用mysqldb fetchall()命令。相反,我会一次读一行。
但是如果我确实想要将内存中的数据内容作为一个懒惰的序列呢?我怎么用Python做呢?
鉴于我没有提供具有特定问题的源代码,我正在寻找的答案是指向Python文档或其他地方的指针或指针以解决此问题。
感谢。
答案 0 :(得分:2)
Python中用于延迟呈现序列的机制是generators。
Generators [sic]函数允许您声明一个行为类似于迭代器的函数,即它可以在for循环中使用。
答案 1 :(得分:1)
“懒惰”代码的基本思想是代码在需要数据之前不会获取数据。
例如,假设我正在编写一个复制文本文件的函数。将整个文件读入内存然后编写整个文件并不是很懒惰。使用.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
答案 2 :(得分:1)
列表几乎与懒惰相反。最好的例子是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
许多将采取清单的地方也会取代发电机。这是真的,Python 3完全取消xrange
,并用它来取代普通的range
。
>>> total2 = sum(xrange(2**30))
>>> print total2
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>
如果你确实需要一个清单,那也很容易。但当然它不再是懒惰。
>>> list(myrange(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
答案 3 :(得分:0)
答案 4 :(得分:0)
但是如果我确实想要将内存中的数据内容作为一个懒惰的序列呢?
以下是制作延迟序列的方法:不是存储项目,而是在请求时动态生成它们,但隐藏在[]
语法后面。我一直忘记SQL API的工作原理,因此以下内容应理解为伪代码。
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()
这可以在许多可以使用list
的情况下使用,但实际上并不存储任何内容。根据需要添加缓存(取决于访问模式)。