【问题标题】:count variable is not updating in recursive function call递归函数调用中计数变量未更新
【发布时间】:2015-09-27 09:57:46
【问题描述】:

以下代码正在查找排列,但 count 变量未更新。任何人都可以指出为什么count 的更改没有反映的错误。

def swap_arr_elems(arr, src_idx, dest_idx):
    tmp = arr[src_idx]
    arr[src_idx] = arr[dest_idx]
    arr[dest_idx] = tmp
    return

def permuate(arr, left, right, output, count):
    if left == right:
        output.append(list(arr))
        count += 1
        #count.append('1')
        return

    for i in range(left, right, 1):
        swap_arr_elems(arr, left, i)
        permuate(arr, left + 1, right, output, count)
        swap_arr_elems(arr, left, i)


if __name__ == '__main__':
    count = 0    
    #count = []
    test_input = ['a', 'b', 'c']
    test_output = []
    permuate(test_input, 0, len(test_input), test_output, count)
    print("count : " + str(count))
    for item in test_output:
        print(item)

编辑 1:

output of the above code is:
count : 0
['a', 'b', 'c']
['a', 'c', 'b']
['b', 'a', 'c']
['b', 'c', 'a']
['c', 'b', 'a']
['c', 'a', 'b']

【问题讨论】:

  • 一些想法:permuate不是一个字;也许你的意思是permute?交换数组元素的更短(和more efficient)方法是使用arr[src_idx], arr[dest_idx] = arr[dest_idx], arr[src_idx]。最后,您可以通过使用yield list(arr) 而不是output.append(list(arr)) 来避免使用output 列表。
  • @Frerich Raabe 我是 python 的初学者,将尝试理解和使用 yield。感谢您指出这一点.. :)

标签: python


【解决方案1】:

您只是在left==right 时增加count 然后从它返回,增加计数不会在调用函数中自动增加它,您可以尝试返回计数然后在函数中接受它它被调用了。

例子-

def permuate(arr, left, right, output, count):
    if left == right:
        output.append(list(arr))
        count += 1
        #count.append('1')
        return count

    for i in range(left, right, 1):
        swap_arr_elems(arr, left, i)
        count += permuate(arr, left + 1, right, output, count)
        swap_arr_elems(arr, left, i)
    return count

if __name__ == '__main__':
    count = 0    
    #count = []
    test_input = ['a', 'b', 'c']
    test_output = []
    count = permuate(test_input, 0, len(test_input), test_output, count)
    print("count : " + str(count))
    for item in test_output:
        print(item)

【讨论】:

    【解决方案2】:

    是的,count 变量的范围仅在主循环中。

    if main 循环中的count 变量和permuate 函数中的计数变量不同。

    如果您想从permuate 函数中获取计数变量的值,则从函数返回计数值并在计数变量中接受。

    演示:

    >>> count = 10
    >>> def test(count):
    ...    count += 1
    ...    print "In test:", id(count)
    ...    return count
    ... 
    >>> count = test(count)
    In test: 149784632
    >>> count 
    11
    

    【讨论】:

    • 从 main 我将 2 个变量(count 和 test_output)传递给 permuatate() 函数。 test_ouput 变量在 permuate 函数内部被修改,修改后的值在 main 内部得到。但是为什么 count 变量的行为不同呢?
    【解决方案3】:

    我个人命名这个可变和不可变的效果不知道它的真名

    Count 是一个整数。也就是说它是一个不可变对象,它的作用域在主函数内,所以它的值不会改变

    即当您执行count+=1 时,会创建一个新对象并且不会返回该对象

    test_output 是一个列表。这是一个可变对象。即使您更改它的值,它也会在同一个列表中更改

    output.append(list(arr)) #adds to the same  test_output list
    

    请参阅link,了解有关可变和非可变对象和行为的更多见解

    根据@brunodesthuilliers output=output+list(arr) 更改输出。这是因为+ 创建了一个新对象,请参阅下面的解释

    >>> out=[1,2,3]
    >>> id(out)
    33535760
    >>> out.append(2)
    >>> id(out)
    33535760
    >>> out=out+[3]
    >>> id(out)
    33535600
    

    【讨论】:

    • 我觉得这个解释更有意义。有没有办法让 count 可变?
    • 有什么方法可以自省,变量类型是可变的还是不可变的?
    • count 已经是不可变的等待会添加一个链接到这句话什么是可变的,哪些是不可变的
    • 它实际上与不变性无关,而是与重新绑定名称和改变对象之间的区别有关。如果 OP 的代码使用output = output + [list(arr)] 而不是output.append(list(arr)),则问题与output 相同。
    • @VigneshKalai 我不认为你明白我的意思。我说的是 OP 的问题是在函数中重新绑定参数的名称不会改变原始对象,这与对象是否可变无关 - 所以如果他使用output = output + [list(arr)] 而不是output.append(list(arr)),他会抱怨output 也没有“更新”。
    【解决方案4】:

    permuate 函数没有返回任何值。它只是以您编写的方式返回控制流。因此,您必须将其修改为return count。此外,您的 swap_arr_elems 函数实际上并没有做任何事情,因为它没有返回任何值。或者,您可以将permuate 中的变量count 定义为global

    【讨论】:

    • 基本上,我来自C/C++背景,学习python。那么你能解释一下你所说的返回计数是强制性的下划线概念吗?在 C++ 引用调用或值调用中,python 中的内容是什么。或者请提供任何链接让我了解它
    【解决方案5】:

    原语是不可变的。当您尝试在函数内部增加计数时,您正在切换函数内部count 所指的内存地址,外部count 保持不变:

    在 CPython 中作为实现细节,对象的id 也是内存地址,所以我们可以清楚地看到这种情况:

    def fn(inside_count):
        print id(inside_count), '- inside_count before increment' 
        inside_count += 1
        print id(inside_count), '- inside_count after increment'
    
    outside_count = 1
    ​
    print id(outside_count), '- outside_count before fn call'
    fn(outside_count)
    print id(outside_count), '- outside_count after fn call'
    

    140536048575784 - outside_count before fn call
    140536048575784 - inside_count before increment
    140536048575760 - inside_count after increment
    140536048575784 - outside_count after fn call 
    

    列表对象的行为是不同的,因为您在对象上调用了 append 函数。 inside_output 引用的内存地址没有变化,内存地址处的对象发生了变化。

    def fn(inside_output):
        print id(inside_output), '- inside_output before append' 
        inside_output.append('1')
        print id(inside_output), '- inside_output after append'
    
    outside_output = []
    ​
    print id(outside_output), '- outside_output before fn call'
    fn(outside_output)
    print id(outside_output), '- outside_output after fn call'
    

    4389007440 - outside_output before fn call
    4389007440 - inside_output before append
    4389007440 - inside_output after append
    4389007440 - outside_output after fn call
    

    话虽如此,既然你的排列在一个列表中,你应该这样做:

    print("count : " + str(len(test_output)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多