python - 生成器类的实例(递归)

标签 python recursion generator

假设我们有这个递归函数(生成器)

data = [1,[21, 22, [231, 232, 233]], [31, 32, 33]]

def listgen(data):
    for each in data:
        if type(each) is int:
            yield str(each)
        elif type(each) is list:
            g = listgen(each)
            for i in g:
                yield i
        else:
            continue
gen = listgen(data)
print ' '.join(gen)

输出是:

1 21 22 231 232 233 31 32 33

现在...我如何将其编写为类,因为我需要为该生成器定义 .close() 方法?

最佳答案

当您在生成器上调用 close 时,它会在当前暂停执行的位置引发 GeneratorExit。您可以捕获该异常,并在重新引发异常之前在 except block 中进行清理(不允许忽略它)。

对于递归生成器来说,这有点复杂,因为您需要手动将异常传播到递归堆栈。但即便如此也不是太难。这是生成器的一个版本,当关闭时,它会在其执行的每个级别上打印“清理”。如果在从示例数据集中生成 231 后立即关闭它,您将得到 3 次,列表中的每一层嵌套一次。在您的实际用例中,您可以将其替换为代码来关闭数据库连接,或者执行您必须执行的任何其他清理工作。

def closable_listgen(data):
    try:
        for each in data:
            if type(each) is int:
                yield str(each)
            elif type(each) is list:
                g = closable_listgen(each)
                try:
                    for i in g:
                        yield i
                except GeneratorExit:
                    g.close()
                    raise
            else:
                continue
    except GeneratorExit:
        print("cleaning up")
        raise

Python 3.3 使这变得更简单,因为新的 yield from 语法会自动为我们传播对 close 生成器链的调用:

def closable_listgen33(data):
    try:
        for each in data:
            if type(each) is int:
                yield str(each)
            elif type(each) is list:
                g = closable_listgen33(each)
                yield from g
            else:
                continue
    except GeneratorExit:
        print("cleaning up")
        raise

为了更好地衡量,以下是如何将生成器实现为一个类(这是您最初要求的):

class list_gen_class(object):
    def __init__(self, data):
        self.iterator = iter(data)
        self.child = None

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            if self.child:
                try:
                    return next(self.child)
                except StopIteration:
                    self.child = None

            value = next(self.iterator)
            if isinstance(value, int):
                return str(value)
            elif isinstance(value, list):
                self.child = list_gen_class(value)

    def close(self):
        if self.child:
            self.child.close()

        print("cleaning up")

关于python - 生成器类的实例(递归),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13512007/

相关文章:

python - 我们可以从同一个服务器/盒子运行 perl 和 python cgi Web 门户吗

python - Python 中的 Levenshtein 距离循环

python - Django 分组依据变量

c# - Java中递归和非递归函数的效率比较

.net - 使用变量、用户定义函数、自定义运算符的最佳免费 C# 数学解析器

scala - 生成器/ block 到迭代器/流的转换

python - 解码 ctypes 结构

java - 谁能告诉我这个递归方法是如何工作的?

c++ - 如何使用分治法和迭代器添加所有 vector 元素?

javascript - 我可以将生成器函数与箭头函数一起使用吗?