如何使用python的yield语句

时间:2012-11-29 21:40:03

标签: python generator yield subset

我有一个项目列表,并希望生成所有可能的子集。因此,我使用带有项目编号的递归函数和所有选定项目的列表作为参数。调用该函数时,将0作为第一个参数,并执行以下操作:

  • 查看索引参数
  • 描述的项目
  • 选择它
  • 它使用递增的索引参数
  • 调用自身
  • 取消选择项目
  • 它使用递增的索引参数
  • 调用自身

我需要可能的子集来优化某些东西,但由于列表会变得很长,我无法查看所有这些。起初我尝试使用蛮力来考虑所有子集,但这是一个天真的想法。现在新的计划是创建一个贪婪算法,它采用第一个“有用的”选择:我想查看所有子集,直到找到一个符合我需要的子集,并认为python的yield语句是正确的选择。这是一些代码:

def bruteForceLeft(selected,index):
    #left is the list of which i need subsets
    #its a gobal variable. to test the code, just make sure that you have a 
    #list called left in scope
    if index==len(left):
        #print(selected)
        yield selected
    else:
        #the algorithm stores the selection in a tuple of two lists
        #that's necessary since there's a second list called right as well
        #I think you can just ignore this. Think of selected as a list that
        #contains the current selection, not a tuple that contains the current
        #selection on the right as well as the left side.
        selected[0].append(left[index])
        bruteForceLeft(selected,index+1)
        selected[0].pop()
        bruteForceLeft(selected,index+1)

#as you can see I pass a tuple of two empty lists to the function.
#only the first one is used in this piece of code
for option in bruteForceLeft( ([],[]) ,0):
    print(option)
    #check if the option is "good"
    #break

输出是:没有

起初我以为我在生成子集时出错了,但在if条件下你可以看到我有一个注释的print语句。如果我取消注释这个print语句,而是注释掉yield语句,那么打印所有可能的选项 - 并且for循环被打破

使用yield语句,代码运行时没有错误,但它也没有做任何事情。

1 个答案:

答案 0 :(得分:4)

问题在于,当您递归调用bruteForceLeft时,所产生的值不会从封闭函数中神奇地产生。所以,你需要自己重新产生它们:

def bruteForceLeft(selected,index):
    #left is the list of which i need subsets
    if index==len(left):
        #print(selected)
        yield selected
    else:
        #the algorithm stores the selection in a tuple of two lists
        #that's necessary since there's a second list called right as well
        #I think you can just ignore this. Think of selected as a list that
        #contains the current selection, not a tuple that contains the current
        #selection on the right as well as the left side.
        selected[0].append(left[index])
        for s in bruteForceLeft(selected,index+1):
            yield s
        selected[0].pop()
        for s in bruteForceLeft(selected,index+1):
            yield s

(编辑:我实际上只测试了这个,你的代码有错误,但我很确定不会重新产生问题)