有时变化的变量 -- Python 2.7

A Sometimes Changing Variable -- Python 2.7

好吧,我写了下面的代码来求任意数量概率的并集(关于这个主题的精彩文章:https://www.thoughtco.com/probability-union-of-three-sets-more-3126263):

#Finds all Intersections
def intersection_finder1(poss, intersection_number):
    #Make Lists of descending possibilities intersection_number times, Works for 2, not 3 
    sub_posses = []
    use = poss
    sub_posses.append(use)
    for i in range(intersection_number - 1):
        #print use[(i+1):], intersection_number
        sub_posses.append(use[(i+1):])
    return sub_posses

def sub_poss_modifier(sub_posses):
    for x in range(len(sub_posses)):
        del sub_posses[x][0]
    return sub_posses

def intersection_finder2(sub_posses, intersection_number, ongoing_sum=0):
    #Iterate over lists for list_item_number_1
    #Increment lists by one 
    #Repeat for last_list length times, 
    #Commented out below are debugging things 
    multi = 1 
    for y in range(len(sub_posses[-1])):
        for i in range(len(sub_posses)):    
            multi = multi * sub_posses[i][y]
            #print multi, sub_posses[i][y], intersection_number
        #print "-----------RESTART------------"
        ongoing_sum += multi
        multi = 1
    if len(sub_posses[-1]) > 1:
        new_lt = sub_poss_modifier(sub_posses)
        return intersection_finder2(new_lt, intersection_number, ongoing_sum)
    return ongoing_sum

def combiner(poss):
    #Sums Possbilities
    total = sum(poss) 
    ongoing_total = total 
    #Adds/Subtracts Combinations 
    for i in range(2, len(poss) + 1):
        #Somehow, poss is changing. I have no idea how. 
        #Say poss is [1/2.0, 1/2.0, 1/2.0]. If you put that in, the function works. If you put poss in, it doesn't 
        print poss
        sub_poss = intersection_finder1(poss, i)
        aors = intersection_finder2(sub_poss, i)
        #print aors, i 
        if i % 2 == 0:
            ongoing_total -= aors
        else:
            ongoing_total += aors
    #Returns total Possbility 
    return ongoing_total

print combiner([1/2.0, 1/2.0, 1/2.0])

它有效,但前提是我进行了特定的更改,其中插入了变量 poss 的值来代替它本身。例如(唯一的变化是 combiner 的第 9 行):

#Finds all Intersections
def intersection_finder1(poss, intersection_number):
    #Make Lists of descending possibilities intersection_number times, Works for 2, not 3 
    sub_posses = []
    use = poss
    sub_posses.append(use)
    for i in range(intersection_number - 1):
        #print use[(i+1):], intersection_number
        sub_posses.append(use[(i+1):])
    return sub_posses

def sub_poss_modifier(sub_posses):
    for x in range(len(sub_posses)):
        del sub_posses[x][0]
    return sub_posses

def intersection_finder2(sub_posses, intersection_number, ongoing_sum=0):
    #Iterate over lists for list_item_number_1
    #Increment lists by one 
    #Repeat for last_list length times, 
    #Commented out below are debugging things 
    multi = 1 
    for y in range(len(sub_posses[-1])):
        for i in range(len(sub_posses)):    
            multi = multi * sub_posses[i][y]
            #print multi, sub_posses[i][y], intersection_number
        #print "-----------RESTART------------"
        ongoing_sum += multi
        multi = 1
    if len(sub_posses[-1]) > 1:
        new_lt = sub_poss_modifier(sub_posses)
        return intersection_finder2(new_lt, intersection_number, ongoing_sum)
    return ongoing_sum

def combiner(poss):
    #Sums Possbilities
    total = sum(poss) 
    ongoing_total = total 
    #Adds/Subtracts Combinations 
    for i in range(2, len(poss) + 1):
        #Somehow, poss is changing. I have no idea how. 
        #Say poss is [1/2.0, 1/2.0, 1/2.0]. If you put that in, the function works. If you put poss in, it doesn't 
        #print poss
        sub_poss = intersection_finder1([1/2.0, 1/2.0, 1/2.0], i)
        aors = intersection_finder2(sub_poss, i)
        #print aors, i 
        if i % 2 == 0:
            ongoing_total -= aors
        else:
            ongoing_total += aors
    #Returns total Possbility 
    return ongoing_total

print combiner([1/2.0, 1/2.0, 1/2.0])

通过进行一些调试,我发现变量 poss 在 for 循环的每次迭代中都会发生变化——因此产生了错误的答案。此外,它仅在代码块#1 中发生变化;在代码块 #2 中,poss 保持不变。到目前为止,我还没有找到我在任何函数中重新定义或更改 poss 的任何实例。此外,即使我在某处更改了 poss,代码块 #1 和 #2 之间的唯一区别是函数 combiner[=39] 第九行中的列表=].然而,块 #2 产生了正确的答案,而块 #1 没有。

块 #1 的终端输出(打印 poss): [0.5, 0.5, 0.5] [0.5, 0.5] 0.75

块 #2 的终端输出(打印 poss): [0.5, 0.5, 0.5] [0.5, 0.5, 0.5] 0.875

到目前为止,为了防止poss发生变化,同时保持一定程度的通用性,我尝试重新定义它并重命名它。我能做些什么来阻止 poss 改变,同时让它计算不同的概率就像改变一个变量一样简单?

顺便说一句,我对编程还很陌生,所以如果有任何建议可以让我的代码更好或者让我自己成为一个更好的程序员,我将不胜感激。

"So far, I haven't been able to find any instance where I redefine or alter poss in any function."

您非常清楚地更改了函数参数 posse 引用的对象。您基本上将 intersection_finder1 的结果传递给 intersection_finder2(恰当的名称...) 在 intersection_finder1 中,您将 posse 附加到 sub_posses。换句话说,在集合的划分中,您使用对象本身来表示不正确的子集。

def intersection_finder1(poss, intersection_number):
    #Make Lists of descending possibilities intersection_number times, Works for 2, not 3 
    sub_posses = []
    use = poss # NOT MAKING A COPY

这表示 posse 引用的对象现在也被 use 引用

    sub_posses.append(use) # now sub_posses includes posse
    for i in range(intersection_number - 1):
        #print use[(i+1):], intersection_number
        sub_posses.append(use[(i+1):])
    return sub_posses

现在,在 intersection_finder2 中,您在 sub_posses 上调用 sub_poss_modifier

def sub_poss_modifier(sub_posses):
    for x in range(len(sub_posses)):
        del sub_posses[x][0]
    return sub_posses

你明确修改sub_posses[0]的地方会是posse

解决办法? 复制。您可以使用内置列表方法 posse.copy(),或易于理解的 python copy-idiom,poss[:].

def intersection_finder1(poss, intersection_number):
    #Make Lists of descending possibilities intersection_number times, Works for 2, not 3 
    sub_posses = []
    use = poss.copy()

以及您不想共享对象但想要相同值的列表的任何其他地方...

备注

为了更好地掌握 Python 变量和值的工作原理,我建议阅读 Ned Batchelder 的所有 Facts and myths about Python names and values.

另外你应该知道这些操作会产生 shallow copies。如果你有比不可变对象列表更复杂的数据结构,比如列表列表或字典列表,你可能需要一个深拷贝。你应该知道其中的区别。

传递列表时,它作为对象传递,而不是作为副本传递,任何赋值都将引用对象作为引用。

您正在将 poss 附加到 intersection_finder1() 中的 sub_posses。这通过其引用附加 poss,而不是副本,即使分配给 use.

sub_poss_modifier() 中,您删除了 sub_posses 的一些元素。这实际上也删除了 poss 的元素。

解决方案是在 intersection_finder1() 中追加到 sub_posses 时复制一份:

sub_posses.append(use[:])