首页 > 解决方案 > 在函数调用之间未重新分配 Set

问题描述

就我而言,我尝试在递归函数调用和更新它之间传递一个集合。通过每次显式传递它作为参数,我希望集合在递归期间不断更新。

对于新的调用,我没有明确传递 set aa 参数,并期望res_set将重定向到一个空的 set 对象。但是在多次调用该函数时,该集合正在更新,就好像 res_set = set()不存在一样。

 def some_recursion_withset(i, res_set = set()):
        res_set.add(random())
        if i > 0:
            i -= 1
            print(res_set)
            some_recursion_withset(i, res_set)
        return res_set

    some_recursion_withset(3)
    some_recursion_withset(1)

这里的输出是:

{0.12513618559206574}
{0.12513618559206574, 0.8224507177489353}
{0.12513618559206574, 0.8224507177489353, 0.7157637106872556}
{0.12513618559206574, 0.8224507177489353, 0.6921901499074943, 0.7157637106872556, 0.8116969360080692}

简化为一个最小的工作示例,为什么在这种情况下res_set = set()被忽略?

from random import random

def some_func_withset(res_set = set()):
    res_set.add(random())
    return res_set

print(some_func_withset())
print(some_func_withset())
print(some_func_withset())

在这种情况下,输出是:

{0.9691623786355451}
{0.9691623786355451, 0.37884137576633103}
{0.9691623786355451, 0.37884137576633103, 0.4482797349507742}

我最感兴趣的是理解这种行为以及实现第一个递归部分的一些好的做法。

标签: pythonpython-3.xscopeset

解决方案


来自Python 教程

默认值仅评估一次。当默认值是可变对象(例如列表、字典或大多数类的实例)时,这会有所不同。例如,以下函数累积在后续调用中传递给它的参数:

res_set = set()只评估一次,这是默认参数,在您的情况下是一个集合对象。当您使用带有默认参数的函数时,您总是得到相同的集合对象,并且由于您不断更新它,集合随着您插入的所有值而增长。

解决您的问题的方法是使用不可变对象作为金丝雀,然后检查您的论点是否是该金丝雀。如果是这种情况,则创建一个新集。在这种情况下使用None是 Python 程序员的约定:

def some_func_withset(res_set = None):
    if res_set is None:
        res_set = set()
    res_set.add(random())
    return res_set

推荐阅读