Python从内部函数改变外部字典

时间:2016-05-30 18:54:23

标签: python pointers dictionary copy

我遇到的行为从我听到的行为在Python中很常见,但我想知道这是默认行为,以及如何防止这种情况。请考虑以下代码:

dic1 = {'a':1, 'b':2}
lis1 = [1, 2]

def somefunc(dic):
    dic.update({'b':20})
    return dic

def otherfunc(lis):
    lis.append(20)
    return lis

for i in range(3):
    dic2 = dic1
    lis2 = lis1
    print(dic2)
    somefunc(dic2)
    print(lis2)
    otherfunc(lis2)

我运行此代码,输出

{'a': 1, 'b': 2}
[1, 2]
{'a': 1, 'b': 20}
[1, 2, 20]
{'a': 1, 'b': 20}
[1, 2, 20, 20]

但为什么不输出以下内容?

{'a': 1, 'b': 2}
[1, 2]
{'a': 1, 'b': 2}
[1, 2]
{'a': 1, 'b': 2}
[1, 2]

我觉得应该输出这个,因为我正在重置dic2lis2。为什么这是默认行为?一旦进入函数,Python不应该复制dic2吗?不应dic2=dic1创建dic1的副本,而不是创建指向内存中相同位置的不同指针? (如果那确实是发生了什么)

我可以通过将dic1替换为dic2 = dic1(或将dic2 = dic1.copy()添加到函数中)来防止dic=dic.copy()发生此行为,但我如何使用列表执行此操作?他们没有复制方法。此外,有一种方法可以让我在默认情况下防止这种情况,而不必在每次处理函数内的字典(或者甚至是Pandas数据帧等)时都记得使用复制方法吗?

干杯

1 个答案:

答案 0 :(得分:1)

在Python上,列表是可变的,这意味着lis2只是lis1的另一个名称,因此它们是同一个对象

这里有两种方法可以在lis2上复制lis1:

package main

import (
    "bytes"
    "fmt"
    "strconv"
)

// Could not find a one-liner that does this :(.
func arrayToString(A []int, delim string) string {

    var buffer bytes.Buffer
    for i := 0; i < len(A); i++ {
        buffer.WriteString(strconv.Itoa(A[i]))
        if i != len(A)-1 {
            buffer.WriteString(delim)
        }
    }

    return buffer.String()
}

func main() {
    A := []int{1, 2, 3}
    fmt.Println(arrayToString(A, ", "))
}

我更喜欢使用strings.Join(A, ", "),因为它更具可读性。