【问题标题】:Replacing a function with something iterable用可迭代的东西替换函数
【发布时间】:2026-02-13 20:45:02
【问题描述】:

简而言之。除了这个,我怎么写: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 声明。 带有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 的想法。他们给的收据对我不起作用,是:

当你看到一个带有yield 语句的函数时,应用这个简单的 了解会发生什么的技巧:

  1. 在函数开头插入一行result = []
  2. 将每个yield expr 替换为result.append(expr)
  3. 在函数底部插入一行return result
  4. 是的 - 不再有 yield 声明!阅读并找出代码。
  5. 将函数恢复为原始定义。

使用它来获取代码而无需 yield 给我这个。代码不工作(函数不可迭代)。 我必须写什么才能让这段代码在没有 yield 的情况下工作?

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

【问题讨论】:

  • 您忘记在上一个函数中缩进第 5 行。

标签: python recursion yield


【解决方案1】:

正如文森特所说,由于第 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

但是,您为什么反对收益率?生成器可生成可读、高效的代码。 Yield Keyword Explained 文章的重点不是要省略它,而是要解释它。

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

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,这会导致调用者停止迭代生成器对象。

【讨论】:

    【解决方案2】:

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

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

    大多数时候你不会在生成器中看到return,因为你并不经常需要它。通常,生成器最后只是“脱落”;解释器在没有遇到return 语句的情况下到达生成器的末尾,然后它知道抛出StopIteration

    这个案例中,代码的作者插入了一个return 语句来“加快”这个过程。当K &lt;= 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
    

    【讨论】: