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

6

我有以下继承关系:

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个回答

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

更新:刚刚测试了上面的代码,运行正常。


sum(1 for _ in self)会做同样的事情。db.fetch_from_query返回什么? - Padraic Cunningham
返回数据库中的行列表 - James Lin

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

并将其用作列表,而不使用生成器的优缺点。


0
如果你想将由get_listings生成的生成器(在非Python术语中称为迭代器)转换为列表,只需使用以下代码:
listings = list(get_listings())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接