代码之家  ›  专栏  ›  技术社区  ›  Lord British

Python:是否可以将生成器和递归函数混合使用?

  •  5
  • Lord British  · 技术社区  · 15 年前

    有没有办法让下面的代码工作?

    add = lambda n: (yield n) or add(n+1)
    

    3 回复  |  直到 15 年前
        1
  •  3
  •   pillmuncher    15 年前
    def add(n):
        yield n
        for m in add(n+1):
            yield m
    

    使用递归生成器,很容易构建复杂的回溯器:

    def resolve(db, goals, cut_parent=0):
        try:
            head, tail = goals[0], goals[1:]
        except IndexError:
            yield {}
            return
        try:
            predicate = (
                deepcopy(clause)
                    for clause in db[head.name]
                        if len(clause) == len(head)
            )
        except KeyError:
            return
        trail = []
        for clause in predicate:
            try:
                unify(head, clause, trail)
                for each in resolve(db, clause.body, cut_parent + 1):
                    for each in resolve(db, tail, cut_parent):
                        yield head.subst
            except UnificationFailed:
                continue
            except Cut, cut:
                if cut.parent == cut_parent:
                    raise
                break
            finally:
                restore(trail)
        else:
            if is_cut(head):
                raise Cut(cut_parent)
    
    ...
    
    for substitutions in resolve(db, query):
        print substitutions
    

    这是一个由递归生成器实现的Prolog引擎。db是表示事实和规则的Prolog数据库的dict。unify()是一个unification函数,它为当前目标创建所有替换,并将更改附加到trail中,以便以后可以撤消。restore()执行撤消操作,is \u cut()测试当前目标是否为“!”,这样我们就可以修剪树枝了。

        2
  •  3
  •   ars    15 年前
        3
  •  0
  •   Tony Veijalainen    15 年前

    n、 n+1,n+2,。。。。

    def add(x):
        while True:
            yield x
            x+=1
    
    for index in add(5):
        if not index<100: break ## do equivalent of range(5,100)
        print(index)
    

    这不是递归的,但我认为这里不需要递归样式。

    基于other answers链接的递归版本,其中生成器调用生成器,但不是递归的:

    from __future__ import generators
    
    def range_from(n):
        yield n
        for i in range_from(n+1):
            yield i
    
    for i in range_from(5):
        if not i<100: break ## until 100 (not including)
        print i