将字典附加到列表时的奇怪行为

时间:2016-10-03 12:51:28

标签: python json python-3.x

我正在将JSON读入我的脚本并构建一个由字典组成的列表。

我的JSON:

{
    "JMF": {
        "table1": {
          "email": "JMF1@fake.com",
          "guests": [
            "test1",
            "test2"
          ]
        },
        "table2": {
          "email": "JMF2@fake.com",
          "guests": [
            "test3"
          ]
        }
    },
    "JMC": {
      "table3": {
        "email": "JMC1@fake.com",
        "guests": [
          "test11"
        ]
      }
    },
    "JMD": {
      "table4": {
        "email": "JMD1@fake.com",
        "guests": [
          "test12"
        ]
      },
      "table5": {
        "email": "JMD2@fake.com",
        "guests": [
          "test17"
        ]
      }
    }
}

我的代码:

def get_json():
    userinfo_list = []
    with open('guest_users.json') as json_file:
        json_file = json.load(json_file)
        keys = json_file.keys()
        for key in keys:
            userinfo = {}
            for table_key in json_file[key].keys():
                email = json_file[key][table_key]['email']
                users_dict = {}
                users_list = []
                for user in json_file[key][table_key]['guests']:
                    users_dict['username'] = user
                    users_dict['password'] = generate_password()
                    users_list.append(users_dict)
                userinfo['company'] = key
                userinfo['email'] = email
                userinfo['userinfo'] = users_list
                userinfo_list.append(userinfo)
                print(userinfo)
                print(userinfo_list)

问题是,只要我的JSON有两个子键(userinfo_list),table*中的值就会被覆盖。

这是我得到的输出,没有意义:

{'userinfo': [{'username': 'test11', 'password': '1fEAg0'}], 'email': 'JMC1@fake.com', 'company': 'JMC'}
[{'userinfo': [{'username': 'test11', 'password': '1fEAg0'}], 'email': 'JMC1@fake.com', 'company': 'JMC'}]
{'userinfo': [{'username': 'test17', 'password': 'A8Jue5'}], 'email': 'JMD2@fake.com', 'company': 'JMD'}
[{'userinfo': [{'username': 'test11', 'password': '1fEAg0'}], 'email': 'JMC1@fake.com', 'company': 'JMC'}, {'userinfo': [{'username': 'test17', 'password': 'A8Jue5'}], 'email': 'JMD2@fake.com', 'company': 'JMD'}]
{'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}
[{'userinfo': [{'username': 'test11', 'password': '1fEAg0'}], 'email': 'JMC1@fake.com', 'company': 'JMC'}, {'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}, {'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}]
{'userinfo': [{'username': 'test2', 'password': 'GagQ59'}, {'username': 'test2', 'password': 'GagQ59'}], 'email': 'JMF1@fake.com', 'company': 'JMF'}
[{'userinfo': [{'username': 'test11', 'password': '1fEAg0'}], 'email': 'JMC1@fake.com', 'company': 'JMC'}, {'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}, {'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}, {'userinfo': [{'username': 'test2', 'password': 'GagQ59'}, {'username': 'test2', 'password': 'GagQ59'}], 'email': 'JMF1@fake.com', 'company': 'JMF'}]
{'userinfo': [{'username': 'test3', 'password': 'U9gP0j'}], 'email': 'JMF2@fake.com', 'company': 'JMF'}
[{'userinfo': [{'username': 'test11', 'password': '1fEAg0'}], 'email': 'JMC1@fake.com', 'company': 'JMC'}, {'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}, {'userinfo': [{'username': 'test12', 'password': '0JSpc0'}], 'email': 'JMD1@fake.com', 'company': 'JMD'}, {'userinfo': [{'username': 'test3', 'password': 'U9gP0j'}], 'email': 'JMF2@fake.com', 'company': 'JMF'}, {'userinfo': [{'username': 'test3', 'password': 'U9gP0j'}], 'email': 'JMF2@fake.com', 'company': 'JMF'}]

1 个答案:

答案 0 :(得分:3)

您将在每次迭代时重新附加相同的单个词典

users_dict = {}  # only one copy of this dictionary is ever created
users_list = []
for user in json_file[key][table_key]['guests']:
    users_dict['username'] = user
    users_dict['password'] = generate_password()
    users_list.append(users_dict)  # appending a reference to users_dict

追加创建副本,因此您可以获得对同一字典的多个引用,并且您只会看到反映的最后一个更改。您使用userinfo字典犯了同样的错误。

在循环中创建一个新词典

users_list = []
for user in json_file[key][table_key]['guests']:
    users_dict = {}
    users_dict['username'] = user
    users_dict['password'] = generate_password()
    users_list.append(users_dict)

您可以在创建字典时直接指定键值对:

users_list = []
for user in json_file[key][table_key]['guests']:
    users_dict = {
        'username': user,
        'password': generate_password()
    }
    users_list.append(users_dict)

这可以通过list comprehension简化为:

users_list = [{'username': user, 'password': generate_password()}
              for user in json_file[key][table_key]['guests']]

请注意,您无需调用dict.keys()来循环字典。您可以使用完全相同的结果直接在上循环。您可能希望循环遍历.items()并避免每次都要查找密钥的值,并在您根本不需要密钥时使用.values()

userinfo_list = []
for company, db in json_file.items():
    for table in db.values():
        userinfo = {
            'company': company,
            'email': table['email'],
            'userinfo': [
                {'username': user, 'password': generate_password()}
                for user in table['guests']]
        }
        userinfo_list.append(userinfo)

每个公司每个表格的字典创建也可以用列表理解来代替,但是此时坚持使用嵌套的for循环可能会更容易理解未来的读者。

以上现在产生:

[{'company': 'JMF',
  'email': 'JMF1@fake.com',
  'userinfo': [{'password': 'random_password_really', 'username': 'test1'},
               {'password': 'random_password_really', 'username': 'test2'}]},
 {'company': 'JMF',
  'email': 'JMF2@fake.com',
  'userinfo': [{'password': 'random_password_really', 'username': 'test3'}]},
 {'company': 'JMC',
  'email': 'JMC1@fake.com',
  'userinfo': [{'password': 'random_password_really', 'username': 'test11'}]},
 {'company': 'JMD',
  'email': 'JMD1@fake.com',
  'userinfo': [{'password': 'random_password_really', 'username': 'test12'}]},
 {'company': 'JMD',
  'email': 'JMD2@fake.com',
  'userinfo': [{'password': 'random_password_really', 'username': 'test17'}]}]

来自您的示例数据(以及我自己对generate_password()的定义)。