列表中循环添加字典出现覆盖现象的问题

本文介绍了一个关于Python中解析XML文件时出现的问题及解决方案。作者通过调整代码逻辑,确保每个用户信息都被正确地转换成独立的字典条目,并最终收集到一个列表中。

这是要解析的xml

<user>
  <userInfo config="/etc" index="1" ip="172.16.1.239" phone="15011262015" realname="田振华" username="tianzh"/>
  <userInfo config="/usr" index="2" ip="1.1.1.1" phone="110" realname="龚凡" username="gongf"/>
  <userInfo config="/lib" index="3" ip="2.2.2.2" phone="120" realname="安吉旺" username="anjw"/>
</user>

这是之前的代码

def get_xml_data(filename='config_new.xml'):

    key_list = ["username","index","realname","config","ip","phone"]

    doc = minidom.parse(filename)
    root = doc.documentElement

    user_nodes = root.getElementsByTagName('userInfo') #根据节点名获取节点集合
    usersinfo=[]     #键值列表 用户信息集合 一个字典表示一行user信息
    adict = {}  
    for node in user_nodes:
        for key in key_list:
            value = node.getAttribute(key)  #根据属性名获取属性值
            if value.strip():#如果属性值不为空(不是"") 则加入到字典中
                adict[key] = value;
        print adict
        usersinfo.append(adict)
        print usersinfo
    return usersinfo
本来是想将从xml中获取出来的信息做为键值做成字典放到列表中,结果返回的usersinfo变成了这样:
[{'username': u'anjw', 'index': u'3', 'realname': u'\u5b89\u5409\u65fa', 'ip': u'2.2.2.2', 'phone': u'120', 'config': u'/lib'}, 
{'username': u'anjw', 'index': u'3', 'realname': u'\u5b89\u5409\u65fa', 'ip': u'2.2.2.2', 'phone': u'120', 'config': u'/lib'}, 
{'username': u'anjw', 'index': u'3', 'realname': u'\u5b89\u5409\u65fa', 'ip': u'2.2.2.2', 'phone': u'120', 'config': u'/lib'}]
显然是不对的,后来查了一下资料,自学了几天python,内部实现虽然不知道,但是显然是最后的解析覆盖了之前的,后来在网上看到的例子受到了启发,我觉得是这样的:我们始终都是更新的adict这个对象,而这个对象只创建了一次,append函数添加的时候只是添加了adict这个对象的地址(我也不知道python这个语言有没有地址这个说法,我只是根据之前学的c语言猜测的。。),所以usersinfo经过三次循环usersinfo的变化是这样的[p1]->[p1,p1]->[p1,p1,p1],p1就是adict地址,所以不管我们怎么循环,usersinfo中的字典都是一样的。
所以我们应该把adict的创建放到for循环中,每次append的时候都是添加的新的字典对象就可以了
解决此问题代 
       def get_xml_data(filename='config_new.xml'):

    key_list = ["username","index","realname","config","ip","phone"]

    doc = minidom.parse(filename)
    root = doc.documentElement

    user_nodes = root.getElementsByTagName('userInfo') #根据节点名获取节点集合
    usersinfo=[]     #键值列表 用户信息集合 一个字典表示一行user信息
    for node in user_nodes:
        adict = {}  #临时字典初始化
        for key in key_list:
            value = node.getAttribute(key)  #根据属性名获取属性值
            if value.strip():#如果属性值不为空(不是"") 则加入到字典中
                adict[key] = value;
        print adict
        usersinfo.append(adict)
        print usersinfo
    return usersinfo

打印usersinfo也正常了

[{‘username’: u’tianzh’, ‘index’: u’1’, ‘realname’: u’\u7530\u632f\u534e’, ‘ip’: u’172.16.1.239’, ‘phone’: u’15011262015’, ‘config’: u’/etc’},
{‘username’: u’gongf’, ‘index’: u’2’, ‘realname’: u’\u9f9a\u51e1’, ‘ip’: u’1.1.1.1’, ‘phone’: u’110’, ‘config’: u’/usr’},
{‘username’: u’anjw’, ‘index’: u’3’, ‘realname’: u’\u5b89\u5409\u65fa’, ‘ip’: u’2.2.2.2’, ‘phone’: u’120’, ‘config’: u’/lib’}]

解决了!

一、字典的概念与特性 很多时候,数据对应的元素之间的顺序是无关紧要的,因为各元素都具有特别的意义,例如存储一些朋友的手机号码,此时用序列来存储数据并不是一个好的选择,Python提供了一个很好的解决方案--使用字典数据类型。 在Python中,字典是属于映射类型的数据结构。字典包含以任意类型的数据结构作为元素的集合,同时各元素都具有与之对应且唯一的键,字典主要通过键来访问对应的元素。字典列表、元组有所不同,后两者使用索引来对应元素,而字典的元素都拥有各自的键,每个键值对都可以看成是一个映射对应关系。此外,元素在字典中没有严格的顺序关系。由于字典是可变的,所以可以对字典对象进行元素的增删改查等基本操作。 二、字典的键与值 字典是以键值对(key:value)为元素构成的集合,可以看成是一种特殊的集合,因此: (1)键值对是通过键(key)来标识的,要求唯一不重复(这是集合的基本要求); (2)键值对的排列是无序的,无法通过索引来访问键值对(但从3.6版本开始,字典开始是有序的,这是新的版本特征); (3)对键的要求:唯一,并且必须是不可变数据类型(否则键就可能出现重复),键一旦创建就不允许修改; (4)值可以是Python的任何数据类型,值可以修改、也可取重复值。 注意: (1)列表等序列类型通过索引访问元素 (2)字典允许通过键来访问对应的值 (3)而集合无法访问单个元素,只能整体访问 三、创建字典 (一)使用花括号{ }创建 只要将字典中的一系列键和值按键值对的格式(key:value,即键:值)传入花括号{ }中,并以逗号将各键值对隔开,即可实现创建字典,具体创建格式如下。 dict={key_1:value_1, key_2:value_2, … , key_n:value_n} 若在花括号0中不传入任何键值对,则会创建一个空字典。如果创建字典时重复传入相同的键,因为键在字典中不允许重复,所以字典最终会采用最后出现的重复键的键值对。 dict1={'myint':1,'myfloat':3.1415,'mystr':'name','myint':100,'mytuple':(1,2,3),'mydict':{}} # 使用花括号创建字典 # 重复键采用最后出现的对应值 dict1 AI写代码 python 运行 empty_dict={} # 创建空字典 empty_dict AI写代码 python 运行 (二)使用dict函数创建 创建字典的另一种方法就是使用dict函数。Python中的dict函数的作用实质上主要是将包含双值子序列的序列对象转换为字典类型,其中各双值子序列中的第1个元素作为字典的键,第2个元素作为对应的值,即双值子序列中包含了键值对信息。所谓双值子序列,实际上就是只包含两个素的序列,例如只包含两个元素的列表['name',Lily']、元组('age',18)、仅包含两个字符的字符串'ab'等。将字典中的键和值组织成双值子序列,然后将这些双值子序列组成序列,例如组成元组(['name','Lily'],('age',18),'ab'),再传入dict函数中,即可转换为字典类型,得到字典对象。除了通过转换方式创建字典外,还可以直接向dict函数传入键和值进行创建,其中须通过“=”将键和值隔开。注意,这种创建方式不允许键重复,否则会返回错误,具体格式如下。 dict(key_1=value_1, key_2=value_2,…, key_n=value_n) 对 dict 函数不传入任何内容时,就可创建一个空字典。 dict1=dict([('int',1),('float',3.1415),('str','name'),('int',100),('tuple',(1,2,3)),('dict',{})]) # 使用dict( )转换列表对象为字典 dict1 AI写代码 python 运行 dict2=dict(zero=0,one=1,two=2) dict2 AI写代码 python 运行 empty_dict=dict() empty_dict AI写代码 python 运行 以上代码中涵盖了创建字典的基本方法,并且能够看到字典中可以包含各种数据类型对象,字典中的值都可以对应到有具体意义的键,可见字典是一种非常灵活和重要的数据结构。 四、提取字典元素 与序列类型不同,字典作为映射类型数据结构,并没有索引的概念,也没有切片操作等处理方法,字典中只有键和值对应起来的映射关系,因此字典元素的提取主要是利用这种映射关系来实现。通过在字典对象后紧跟方括号[ ]包括的键可以提取相应的值,具体使用格式为dict[key],即字典[键]。同时应注意,传入的键要存在于字典中,否则会返回一个错误。 dict3={'spring':(3,4,5),'summer':(6,7,8),'autumn':(9,10,11),'winter':(12,1,2)} dict3['autumn'] # 提取键为’autumn’的对应值 dict3['Spring'] # 提取字典中不存在的键’Spring’所对应的值 AI写代码 python 运行 为避免出现上述传入键不存在而导致出错的现象Python提供了两种处理方法。 (一)提取前使用in语句测试键是否存在 错误主要是因为传入的键不存在而导致的,因此在传人键之前,尝试去检查字典中是否包含这个键;若不存在,则不进行提取操作。这种功能具体可以使用in语句来实现,代码如下所示。 'Spring' in dict3 # 使用in检查传入键是否存在 False AI写代码 python 运行 (二)使用字典方法get 字典方法get能够灵活地处理元素的提取,向get 函数传人需要的键和一个代替值即可,无论键是否存在。若只传人键,当键存在于字典中时,函数会返回对应的值;当键不存在时,函数会返回None,屏幕上什么都不显示。若同时也传入代替值,当键存在时,返回对应值;当键不存在时,返回这个传入的代替值,而不是None,代码如下所示。 dict3.get('summer') # 传入存在的键并返回对应值 (6, 7, 8) dict3.get('Spring') # 仅传入不存在的键,不显示任何东西 print(dict3.get('Spring')) # 打印函数返回的结果 None dict3.get('Spring','Not in this dict') # 传入不存在的键并返回代替值 'Not in this dict' AI写代码 python 运行 五、字典的增删改查 (一)增添字典元素 1、使用键访问赋值增添 利用字典元素提取方法传入一个新的键,并对这个键进行赋值操作,字典中会产生新的键值对,这种操作可能会因为键不存在而出现错误。 dict_name[new_key]=new_value country=dict(China='Beijing',America='Washington',Britain='London') # 使用dict()函数创建字典 country['Russian']='Moscow' # 增添元素 country AI写代码 python 运行 2、使用update方法 字典方法update能将两个字典中的键值对进行合并,传人字典中的键值对会复制添加到调用函数的字典对象中。若两个字典中存在相同键,传入字典中的键所对应的值会替换掉调用函数字典对象中的原有值,实现值更新的效果。 country=dict(China='Beijing',America='Washington',Britain='London') others=dict(Australia='Canberra',Canada='OTTAWA') country.update(others) # 使用update( )函数增添多个元素 country AI写代码 python 运行 (二)删除字典元素 1、使用del语句删除字典元素 使用del语句删除元素的具体格式为: del dict_name[key] country=dict(China='Beijing',America='Washington',Britain='London') del country['America'] country AI写代码 python 运行 2、使用pop语句删除字典元素 向pop语句传人需要删除的键,则会返回对应的值,并在字典当中移除相应的键值对。若将函数返回的结果赋值给变量,就相当于从字典当中抽离出了值。 country=dict(China='Beijing',America='Washington',Britain='London') old_value=country.pop('America') # 将键对应的值赋值给变量,并删除键值对 old_value country AI写代码 python 运行 3、使用clear删除字典元素 clear会删除字典中的所有元素,最终会返回一个空字典。 country=dict(China='Beijing',America='Washington',Britain='London') country_copy=country.copy() country_copy.clear() # 清空副本字典内容 country_copy AI写代码 python 运行 (三)修改字典元素 现在,字典country 已经被删除了字母全为大写的值,但发现还有一个值全为小写,为统一字典中各元素的格式,需要对这个值进行修改。 为修改字典中的某个元素,同样可以使用键访问赋值来修改,格式为: dict_name[key]= new value 由此可以看出,赋值操作在字典当中非常灵活,无论键是否存在于字典中,所赋予的新值都会覆盖或增添到字典中,这很大程度上方便了对字典对象的处理,代码如下所示。 country=dict(China='Beijing',Canada='OTTAWA',Britain='London') country['Canada']='Ottawa' # 直接将新值赋值给对应元素 country AI写代码 python 运行 (四)查询字典元素信息 字典方法中有3种方式可以用于提取键值信息。 (1)keys:用于获取字典中的所有键。 (2)values:用于获取字典中的所有值。 (3)itmes:得到字典中的所有键值对。 这3种方式所返回的结果是字典中键、值或键值对的迭代形式,都可以通过list函数将返回结果转换为列表类型,同时可以配合in的使用,判断值和键值对是否存在于字典当中。 country=dict(China='Beijing',Canada='OTTAWA',Britain='London') # 获取所有键 all_keys=country.keys() # 使用函数keys()得到全部键 all_keys list(all_keys) # 将键的迭代形式转换为列表 # 获取所有值 all_values=country.values() # 使用函数values()得到全部值 all_values list(all_values) # 将值的迭代形式转换为列表 # 获取所有键值对信息 all_items=country.items() # 使用函数items()得到全部键值对 all_items list(all_items) # 将键值对迭代形式转换为列表 AI写代码 python 运行 补充: 因为d.keys()返回结果是可迭代的,可以直接用在for…in循环中,而无需先转换成列表: for key in d.keys(): print(key) AI写代码 python 运行 对于d.values()和d.items()也有相同的用法! 以上便是字典所使用的常用处理方法,具体实现了字典元素的增删改查等重要操作。这里所介绍的字典方法和函数可以实现对字典的一些简单处理,如果需要对字典进行更复杂、更高级的处理,就需要将这些方法进行灵活组合运用。例如利用值来查询所有与之对应的键,代码如下所示。 # 提取字典中值为True所对应的键 test={'A':100,'B':300,'C':True,'D':200} keys=list(test.keys()) # 提取字典中所有键 values=list(test.values()) # 提取字典中所有值 keys values keys[values.index(True)] # 故利用值True的索引来提取对应的键 AI写代码 python 运行 六、字典的常用操作方法 使用语法形式是: <字典变量>.<方法名称>(<方法参数>) 1、d.get(key, default)根据键信息查找并返回值信息,如果key存在则返回相应值,否则返回默认值,第二个元素default可以省略,如果省略则默认值为空。 d = {"201801":"小明", "201802":"小红", "201803":"小白"} d.get('201802') '小红' d.get('201804') d.get('201804', '不存在') '不存在' AI写代码 python 运行 2、d.pop(key, default)根据键信息查找并取出值信息,如果key存在则返回相应值,否则返回默认值,第二个元素default可以省略,如果省略则默认值为空。相比d.get()方法,d.pop()在取出相应值后,将从字典中删除对应的键值对。 d = {"201801":"小明", "201802":"小红", "201803":"小白"} d.pop('201802') '小红' print(d) {'201801': '小明', '201803': '小白'} d.pop('201804', '不存在') '不存在' AI写代码 python 运行 3、d.popitem()随机从字典中取出一个键值对,以元组(key, value)形式返回。取出后从字典中删除这个键值对。 d = {"201801":"小明", "201802":"小红", "201803":"小白"} print(d.popitem()) ('201803', '小白') d {'201801': '小明', '201802': '小红'} AI写代码 python 运行 4、与其他组合类型一样,字典可以遍历循环对其元素进行遍历,基本语法结构如下: for <变量名> in <字典名>: <语句块> for循环返回的变量名是字典的键值。如果需要获得键对应的值,可以在语句块中通过get()方法获得。 d = {"201801":"小明", "201802":"小红", "201803":"小白"} for k in d: print("字典的键和值分别是:{}和{}".format(k, d.get(k))) 字典的键和值分别是:201801和小明 字典的键和值分别是:201802和小红 字典的键和值分别是:201803和小白 AI写代码 python 运行 小结 #字典常用函数示例 dt={'a':1,'b':2,'c':3} #输出字典所有的键 for k in dt.keys(): print(k,end=' ') print() #输出字典所有的值 for v in dt.values(): print(v,end=' ') print() #分开输出字典中所有的键和值 for k,v in dt.items(): print((k,v),end=' ') print() #如果循环中只给出了字典名,而未使用明确的方法,输出的是字典的键,此情况与第1种情况等价 for k in dt: print(k,end=' ') AI写代码 python 运行 运行结果: a b c 1 2 3 ('a', 1) ('b', 2) ('c', 3) a b c AI写代码 python 运行 如果要按顺序输出字典的所有键,则可以使用sorted()函数: for k in sorted(dt.keys()): print(k,end=' ') print() AI写代码 python 运行 类似的,如果使用 list()函数把字典转换成列表,则也只是把字典的键作为了列表元素。 七、字典的常用操作函数 操作函数 描述 len(d) 字典d的元素个数(长度) min(d) 字典d中键的最小值 max(d) 字典d中键的最大值 例一 d={"201801":"小明","201802":"小红","201803":"小白"} min(d) max(d) AI写代码 python 运行 输出结果: '201801' '201803' AI写代码 python 运行 例二 例:要求把两个列表的元素按位置关系合成为字典。 法一:使用for循环 Lst1=['a','b','c'] Lst2=[1,2,3] Dct1={} for i in range(len(Lst1)): Dct1[Lst1[i]]=Lst2[i] print(Dct1) {'a': 1, 'b': 2, 'c': 3} AI写代码 python 运行 法二:使用字典推导式来实现 Lst1=['a','b','c'] Lst2=[1,2,3] Dct1={Lst1[i]: Lst2[i] for i in range(len(Lst1))} print(Dct1) {'a': 1, 'b': 2, 'c': 3} AI写代码 python 运行 法三:使用zip函数 Lst1=['a','b','c'] Lst2=[1,2,3] Dct1={} Dct1=dict(zip(Lst1,Lst2)) print(Dct1) {'a': 1, 'b': 2, 'c': 3} AI写代码 python 运行 根据以上内容写一篇小红书笔记
07-13
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值