我有以下继承:
class Processor(object):
def get_listings(self):
"""
returns a list of data
"""
raise NotImplemented()
def run(self):
for listing in get_listings():
do_stuff(listing)
class DBProcessor(Processor):
def get_listings(self):
"""
return a large set of paginated data
"""
...
for page in pages:
for data in db.fetch_from_query(...):
yield data
虽然这有效,但在len(self.get_listings())
或任何其他列表操作上都会失败。
我的问题是如何重构DBProcessor.get_listings
可以处理列表操作的代码,但是当迭代器调用它会返回生成器时?
答案 0 :(得分:4)
我想我有个主意:
class DBListings(object):
def __iter__(self):
for page in pages:
for data in db.fetch_from_query(...):
yield data
def __len__(self):
return db.get_total_from_query(...)
"""
Or the following
counter = 0
for x in self:
counter += 1
return counter
"""
class DBProcessor(Processor):
def get_listings(self):
"""
return a large set of paginated data
"""
return DBListings()
更新:刚刚测试了上面的代码,有效。
答案 1 :(得分:0)
这取决于您要支持的list
- 操作。当默认为iter
时,其中一些仅消耗生成器。
如果您事先知道操作的结果(例如len
),您可以通过创建GeneratorContainer来绕过它:
class GeneratorContainer():
def __init__(self, generator, length):
self.generator = generator
self.length = length
def __iter__(self):
return self.generator
def __len__(self):
return self.length
result = GeneratorContainer(DBProcessor().get_listings(), length)
# But you need to know the length-value.
调用len
将不会尝试迭代生成器。但是你总是可以创建一个列表,这样就不会耗尽数据:
result = list(DBProcessor().get_listings())
并将其用作没有生成器优缺点的列表。
答案 2 :(得分:0)
如果您希望将get_listings
生成的生成器(非Python说话中的迭代器)转换为列表,只需使用
listings = list(get_listings())