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

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是要解析的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’}]

解决了!

<think>好的,用户想了解如何在编程中打印散列表,并需要示例代码。首先,我需要回忆散列表的基本结构和实现方式。散列表通常由数组和哈希函数组成,处理冲突的方法有开放寻址法和链地址法等。打印散列表的关键是遍历每个桶,并输出其中的键值对。接下来,考虑不同编程语言的实现差异。用户可能使用C++、Python或Java,但根据用户之前的引用中有C++和C的代码示例,可能更倾向于这些语言。不过用户的问题中没有明确指定语言,所以应该提供几种常见语言的例子。 然后,分析如何遍历散列表。例如,在链地址法中,每个桶是一个链表,需要遍历链表中的所有节点。而在开放寻址法中,需要遍历整个数组,跳过空的位置。需要确保代码示例覆盖这两种情况,并且输出格式清晰。还要注意代码的可读性,比如在Python中使用字典实现散列表,但用户可能指的是自定义实现的散列表结构,而不是内置的字典。因此,应该展示如何手动实现并打印,而不是直接打印内置结构。 另外,用户提供的引用中有C++的ModulusHash类,可以参考这个结构来设计打印函数。例如,在C++中,遍历每个桶,输出索引和对应的键值。同样,在Python中,可能需要遍历每个桶中的链表节点。 最后,检查代码是否符合LaTeX格式要求,确保数学表达式正确使用$...$,独立公式用$$...$$。但在这个问题中,可能数学内容不多,主要集中在代码示例上。需要确保代码块正确标记,语法正确,并且用中文解释每个步骤。</think>### 如何打印散列表的内容? 打印散列表需要根据其底层实现方式遍历所有存储位置(桶),并输出有效的键值对。以下是不同编程语言中的实现示例: --- #### **C++链地址法实现** ```cpp #include <iostream> #include <vector> #include <list> class HashTable { private: std::vector<std::list<std::pair<int, std::string>>> buckets; int size; int hashFunction(int key) { return key % size; } public: HashTable(int tableSize) : size(tableSize) { buckets.resize(size); } void insert(int key, const std::string& value) { int index = hashFunction(key); buckets[index].emplace_back(key, value); } // 打印散列表所有内容 void printTable() { for (int i = 0; i < size; ++i) { std::cout << "Bucket " << i << ": "; for (const auto& pair : buckets[i]) { std::cout << "[" << pair.first << ":" << pair.second << "] "; } std::cout << std::endl; } } }; int main() { HashTable ht(5); ht.insert(10, "Apple"); ht.insert(21, "Banana"); ht.printTable(); return 0; } ``` **输出示例**: ``` Bucket 0: [10:Apple] Bucket 1: [21:Banana] Bucket 2: Bucket 3: Bucket 4: ``` --- #### **Python开放寻址法实现** ```python class HashTable: def __init__(self, size): self.size = size self.table = [None] * size def _hash(self, key): return key % self.size def insert(self, key, value): index = self._hash(key) while self.table[index] is not None: index = (index + 1) % self.size self.table[index] = (key, value) def print_table(self): for i in range(self.size): entry = self.table[i] if entry: print(f"Slot {i}: {entry[0]} -> {entry[1]}") else: print(f"Slot {i}: Empty") # 测试 ht = HashTable(7) ht.insert(25, "Orange") ht.insert(12, "Grape") ht.print_table() ``` --- ### 关键实现步骤 1. **遍历所有桶**:通过循环访问散列表的每个存储位置 2. **处理冲突结构**: - 链地址法:遍历链表中的每个节点 - 开放寻址法:直接检查数组元素是否为空 3. **格式化输出**:显示桶索引和对应的键值对 4. **空值处理**:明确标记未使用的存储位置 --- ### 性能优化建议 1. 添加`load factor`监控,当超过阈值时触发扩容[^2] 2. 对长链表进行树化(如Java 8的HashMap实现) 3. 使用二次探查法减少开放寻址中的聚集现象 --- ### 实际应用场景 1. 数据库索引的快速查找 2. 编程语言字典类型的底层实现 3. 缓存系统(如Redis)的键值存储[^3] ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值