用可迭代的东西替换函数

时间:2012-07-23 15:55:04

标签: python recursion yield

简而言之。如何编写除此之外的其他内容:for another in combinationOfK(K-1, L[i+1:]):我的函数combinationOfK(...)不可迭代。

我正在尝试理解来自here的代码,解决方案。 Problem 26: Generate the combinations of K distinct objects chosen from the N elements of a list我知道收益率是多少。但是我试图在没有 yield语句的情况下编写代码。带有yield语句的代码就是这个。

def combination(K, L):
    if K<=0:
        yield []
        return
    for i in range(len(L)):
        thisone = L[i:i+1]
        for another in combination(K-1, L[i+1:]):
            yield thisone + another

The question, yield-keyword-explained让我知道我可以取代产量。他们给予的接受,这对我不起作用,是:

  

当您看到包含yield语句的函数时,请轻松应用此功能   理解会发生什么的技巧:

     
      
  1. 在功能开头插入一行result = []
  2.   
  3. 将每个yield expr替换为result.append(expr)
  4.   
  5. 在功能底部插入一行return result
  6.   
  7. 耶 - 没有更多yield陈述!阅读并找出代码。
  8.   
  9. 将功能恢复为原始定义。
  10.   

使用它来获得没有收益的代码给我这个。代码不起作用(该函数不可迭代)。 我需要编写什么才能使这些代码无损地工作?

def combinationOfK(K,L):
    result = []
    if K <= 0:
        result.append([])
        return
    for i in range(len(L)):
        thisone = L[i:i+1]
        for another in combinationOfK(K-1, L[i+1:]):  # the error
            result.append(thisone + another)
    return result

我正在使用此代码来测试函数,

the_list = ['a','b','c','d','e']
print list(combinationOfK(2, the_list))

引发错误TypeError: 'NoneType' object is not iterable

2 个答案:

答案 0 :(得分:2)

正如Vincent所说,由于第5行,你的函数返回None。将其更改为:

def combinationOfK(K,L):
    result = []
    if K <= 0:
        result.append([])
        return result
    for i in range(len(L)):
        thisone = L[i:i+1]
        for another in combinationOfK(K-1, L[i+1:]):  # the error
            result.append(thisone + another)
    return result

但是,为什么你反对收益?生成器可实现可读,高效的代码。产量关键字解释文章的要点不是免除​​它,而是解释它。

在您发布的生成器代码中:

def combination(K, L):
    if K<=0:
        yield []
        return
    for i in range(len(L)):
        thisone = L[i:i+1]
        for another in combination(K-1, L[i+1:]):
            yield thisone + another

return语句与return在普通函数中的含义不同。在生成器中,return立即引发StopIteration,这会导致调用者停止迭代生成器对象。

答案 1 :(得分:2)

问题是原始代码以不寻常的方式使用return

def combination(K, L):
    if K<=0:
        yield []
        return    #  <--- hmmm

大多数情况下,您不会在生成器中看到return,因为您不经常需要它。通常情况下,发电机最终会“脱落”;解释器到达生成器的末尾而不会遇到return语句,然后它知道抛出StopIteration

这个的情况下,代码的编写者插入了一个return语句来“快点”进程。当K <= 0时,没有更多工作要做,因此生成器可以抛出StopIteration - 但是如果没有return语句,它将进入for循环,生成结果不正确。在我看来,更明确的方法就是这样:

def combination(K, L):
    if K<=0:
        yield []
    else:
        for i in range(len(L)):
            thisone = L[i:i+1]
            for another in combination(K-1, L[i+1:]):
                yield thisone + another

现在转换按预期工作:

def combination2(K, L):
    result = []
    if K <= 0:
        result.append([])
    else:
        for i in range(len(L)):
            thisone = L[i:i + 1]
            for another in combination2(K - 1, L[i + 1:]):
                result.append(thisone + another)
    return result