Python如何将方法的结果转换为生成器

时间:2016-04-17 22:56:24

标签: python iterator generator

我有以下继承:

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可以处理列表操作的代码,但是当迭代器调用它会返回生成器时?

3 个答案:

答案 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())