为什么列表中变量的值会在Python中发生变化?

时间:2016-11-20 22:05:02

标签: python json variables

我不理解Python 2.7.12 ...

的这种行为

请验证下面粘贴的代码:

test = [(('AAA_1', 'BBB_1', 'CCC_1'), 1), (('AAA_2', 'BBB_2', 'CCC_2'), 2),(('AAA_3', 'BBB_3', 'CCC_3'), 3), (('AAA_4', 'BBB_4', 'CCC_4'), 4)]
for i, j in enumerate(test):
    for k, l in enumerate(j[0]):
        if k == 0:
            dc['first'] = l
        elif k == 1:
            dc['second'] = l
        elif k == 2:
            dc['third'] = l
        elif k == 3:
            dc['fourth'] = l
    c.append(dc)
    print "/n"
    print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx"
    print dc
    print json.dumps(c, indent=1)
    print c

print json.dumps(c, indent=1)

上面显示的代码结果存储在公共pastebin:http://pastebin.com/GkrTyseg

对我来说有点奇怪: 通过附加列表:c我想收到词典列表。这个词典可以代表每种类型的AAA,BBB,CCC元组。我使用字典将其转换为json,以便通过webservices轻松地使用这些数据。

无论如何,我希望收到json:

 {
  "second": "BBB_1",
  "third": "CCC_1",
  "first": "AAA_1"
 },
 {
  "second": "BBB_2",
  "third": "CCC_2",
  "first": "AAA_2"
 },
 {
  "second": "BBB_3",
  "third": "CCC_3",
  "first": "AAA_3"
 },
 {
  "second": "BBB_4",
  "third": "CCC_4",
  "first": "AAA_4"
 }

但实际结果是:

 {
  "second": "BBB_4",
  "third": "CCC_4",
  "first": "AAA_4"
 },
 {
  "second": "BBB_4",
  "third": "CCC_4",
  "first": "AAA_4"
 },
 {
  "second": "BBB_4",
  "third": "CCC_4",
  "first": "AAA_4"
 },
 {
  "second": "BBB_4",
  "third": "CCC_4",
  "first": "AAA_4"
 }

为什么之前附加的值会将其值更改为新值?

当我使用而不是list时,我收到了相同的结果:c使用额外的字典,以获得比使用列表更漂亮的json。但结果是一样的...... 我尝试使用(而不是列表:c):

main_dc[i+1] = dc 

如何防止不更改列表或字典元素的值?

3 个答案:

答案 0 :(得分:0)

您应该将字典的副本附加到列表中(实际上是一个新的字典,其引用不是dc),因此不会对先前附加的同一对象进行字典的进一步更改: / p>

c.append(dc.copy())

答案 1 :(得分:0)

你可以使用深copy(虽然还有其他方法)。当你不使用深度并使用引用的类似对象时,就会发生这种情况!这里是您的代码更改深拷贝,并正常工作:

import copy
import json
test = [(('AAA_1', 'BBB_1', 'CCC_1'), 1), (('AAA_2', 'BBB_2', 'CCC_2'), 2),(('AAA_3', 'BBB_3', 'CCC_3'), 3), (('AAA_4', 'BBB_4', 'CCC_4'), 4)]
c = []
for i, j in enumerate(test):
    dc = copy.deepcopy({}) #or simply dc = {}
    for k, l in enumerate(j[0]):
        if k == 0:
            dc['first'] = l
        elif k == 1:
            dc['second'] = l
        elif k == 2:
            dc['third'] = l
        elif k == 3:
            dc['fourth'] = l
    c.append(dc)
    print "/n"
    print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXx"
    print dc
    print json.dumps(c, indent=1)
    print c

print json.dumps(c, indent=1)

这是一个很好的例子,可以看到深拷贝和浅拷贝的区别

In [1]: l1 = [1,2,3,4]

In [2]: l2 = l1

In [3]: l3 = copy.deepcopy(l1) #import copy

In [4]: l2[0] = 0

In [5]: l1
Out[5]: [0, 2, 3, 4]

In [6]: l2
Out[6]: [0, 2, 3, 4]

In [7]: l3
Out[7]: [1, 2, 3, 4]

答案 2 :(得分:0)

在您的代码中缺少dc的定义,但我假设您在所有循环之前定义。这意味着您不会在每次迭代中生成新的dc对象。相反,您重复使用第一个,覆盖其内容,并将其一次又一次地附加到c。 "追加"这意味着,指向同一对象的四个链接将附加到c

在进入dc循环之前,您应该在i, j循环内移动k, l 的定义。这会在i, j循环的每次迭代中创建一个新对象。

...
for i, j in enumerate(test):
    dc = {}
    for k, l in enumerate(j[0]):
    ...