不覆盖现有键值对的情况下更新字典?

4
我可以帮助您翻译以下内容,这是关于编程的:

我有一个输入文件如下,我可以从中构建我的字典

一般格式

<IP_1>
KEY_1=VALUE_1
KEY_2=VALUE_2

<IP_2>
KEY_1=VALUE_1
KEY_2=VALUE_2

例子
192.168.1.1
USER_NAME=admin
PASSWORD=admin123

192.168.1.2
USER_NAME=user
PASSWORD=user123

预期的字典应该长这样:

>>print dictionary_of_ip
{'192.168.1.1':{'USER_NAME'='admin','PASSWORD'='admin123'},
 '192.168.1.2':{'USER_NAME'='user','PASSWORD'='user123'}}

基本上是一个字典嵌套字典
以下是我的代码:
def generate_key_value_pair(filePath, sep='='):
    dict_of_ip = {}
    slave_properties = {}
    with open(filePath, "rt") as f:
        for line in f:
            stripped_line = line.strip()
            if stripped_line and stripped_line[0].isdigit():
                #print 'Found Ip'
                ip = stripped_line
                dict_of_ip[ip] = ''
            elif stripped_line and stripped_line[0].isupper():
                #print "Found attributes")
                key_value = stripped_line.split(sep)
                key = key_value[0].strip()
                value = key_value[1].strip()
                slave_properties[key] = value
                dict_of_ip[ip] = slave_properties

    return dict_of_ip

我能够按预期获取第一个IP及其属性,但是来自第二个IP的第二组值正在覆盖第一个IP的值。
>>print dict_of_ip
{'192.168.1.1': {'USER_NAME': 'user', 'PASSWORD': 'user123'},
 '192.168.1.2': {'USER_NAME': 'user', 'PASSWORD': 'user123'}}

"

dict_of_ip[ip] = slave_properties 导致了覆盖。我该如何防止 '192.168.1.2' 键的值覆盖第一个值?

"

1
如果ip不在ip字典中,则dict_of_ip[ip] = slave_properties应该可以解决问题... - Jean-François Fabre
多字典不是更容易吗? - Mangohero1
提示:变量slave_properties在其生命周期内引用了多少个不同的字典? - jwodder
所以你的意思是:如果键已经存在,则不要更新它,只创建。看看我的注释,只需测试字典中是否已经有该键... - Jean-François Fabre
可能是更新嵌套字典中已存在键的数据的重复问题。 - Tadhg McDonald-Jensen
@Jean-FrançoisFabre,我按照您的建议尝试了一下,但我收到的输出是{'192.168.1.1': '', '192.168.1.2': ''}。 - Abhay Hegde
6个回答

0

试试这个:

def generate_key_value_pair(filePath, sep='='):
    dict_of_ip = {}
    with open(filePath, "rt") as f:
        for line in f:
            stripped_line = line.strip()
            if stripped_line and stripped_line[0].isdigit():
                #print 'Found Ip'
                slave_properties = {}
                ip = stripped_line
                dict_of_ip[ip] = ''
            elif stripped_line and stripped_line[0].isupper():
                #print "Found attributes")
                key_value = stripped_line.split(sep)
                key = key_value[0].strip()
                value = key_value[1].strip()
                slave_properties[key] = value
                dict_of_ip[ip] = slave_properties

    return dict_of_ip

你使用了相同(修改后的)dict。我没有故意改变你的代码逻辑,只是将slave_properties = {}更改为应该在的位置。

你甚至可以删除你的slave_properties并仅使用dict

def generate_key_value_pair(filePath, sep='='):
    dict_of_ip = {}
    with open(filePath, "rt") as f:
        for line in f:
            stripped_line = line.strip()
            if stripped_line and stripped_line[0].isdigit():
                #print 'Found Ip'
                ip = stripped_line
                dict_of_ip[ip] = {}
            elif stripped_line and stripped_line[0].isupper():
                #print "Found attributes")
                key_value = stripped_line.split(sep)
                key = key_value[0].strip()
                value = key_value[1].strip()
                dict_of_ip[ip][key] = value

    return dict_of_ip

0

你不应该在循环中写 slave_properties = {},因为这样会导致你引用同一个字典对象,而不是创建一个新的字典。

slave_properties[key] = value
dict_of_ip[ip] = slave_properties

0

如果您使用Python的高性能数据类型,这将变得更加容易和高效。例如,以下是相同代码使用defaultdict而不是创建自己的集合类型。

from collections import defaultdict

dict_of_ip = defaultdict(dict)   # This creates a dictionary of dictionaries for you.

ip = None  
for line in f:
    stripped_line = line.strip() 
    if stripped_line and stripped_line[0].isdigit():
        ip = stripped_line  # The value for the ip only changes if a new 
                            # IP is detected. Otherwise the algorithm proceeds
                            # with the older IP address to the nested dict. 

    elif stripped_line and stripped_line[0].isupper():
        key_value = stripped_line.split(sep)  
        key = key_value[0].strip()
        value = key_value[1].strip()
        dict_of_ip[ip][key] = value # IP set in the earlier if-loop. 

更具体地说,你之前出现错误的原因是你在编辑每个子字典时都使用了同一个slave_properties字典。因此,一个子字典中的更改会传播到其他子字典中。

0
你可以选择使用正则表达式和字典推导式的组合方式:
import re

string = """
192.168.1.1
USER_NAME=admin
PASSWORD=admin123

192.168.1.2
USER_NAME=user
PASSWORD=user123
"""

regex = re.compile(r"""
    ^
    (?P<ip>\d+\.\d+\.\d+\.\d+)[\n\r]
    USER_NAME=(?P<user>.+)[\r\n]
    PASSWORD=(?P<password>.+)
    """, re.MULTILINE | re.VERBOSE)

users = {match.group('ip'):
            {'USER_NAME': match.group('user'), 
            'PASSWORD': match.group('password')}
            for match in regex.finditer(string)}

print(users)
# {'192.168.1.2': {'USER_NAME': 'user', 'PASSWORD': 'user123'}, '192.168.1.1': {'USER_NAME': 'admin', 'PASSWORD': 'admin123'}}

ideone.com 上看它运行。这是相应的 regex101.com 上的演示


0
只需将slave_properties的初始化移动到识别出IP地址后立即进行。这样,每次遇到一个IP地址时,它都会开始为空(我还删除了您不必要的初始化dict_of_ip[ip])。
from pprint import pprint

def generate_key_value_pair(filePath, sep='='):
    dict_of_ip = {}

    with open(filePath, "rt") as f:
        for line in f:
            line = line.strip()
            if line and line[0].isdigit():  # ip?
                slave_properties = {}  # initialize
                ip = line
            elif line and line[0].isupper():
                key_value = line.split(sep)
                key = key_value[0].strip()
                value = key_value[1].strip()
                slave_properties[key] = value
                dict_of_ip[ip] = slave_properties

    return dict_of_ip

result = generate_key_value_pair('ips.txt')
pprint(result)

输出:

{'192.168.1.1': {'PASSWORD': 'admin123', 'USER_NAME': 'admin'},
 '192.168.1.2': {'PASSWORD': 'user123', 'USER_NAME': 'user'}}

0

使用切片和字典推导式的紧凑解决方案:

with open("data.txt", "r") as f:
    f = [i.strip() for i in f.readlines()]
    ipdict = {ip: {'USER_NAME': user[10:], 'PASSWORD': password[9:]} 
              for ip, user, password in zip(f[0::4], f[1::4], f[2::4])}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接