【问题标题】:Python3 dictionary values being overwrittenPython3 字典值被覆盖
【发布时间】:2018-02-05 17:29:01
【问题描述】:

我的字典有问题。我正在使用 Python3。我确信有一些我没有看到的简单的东西。

我正在从文件中读取行以创建字典。每行的前 3 个字符用作键(它们是唯一的)。从那里,我根据该行其余部分的信息创建一个列表。每 4 个字符构成列表的一个成员。创建列表后,我会写入目录,其中列表是值,行的前三个字符是键。

问题是,每次我向字典中添加一个新的键:值对时,它似乎都会覆盖(或更新)之前编写的字典条目中的值。键很好,只是值改变了。因此,最后,所有键的值都与文件中最后一行的列表等效。

我希望这很清楚。任何想法将不胜感激。

一个sn-p的代码如下

formatDict = dict()  
sectionList = list()  
for usableLine in formatFileHandle:  
    lineLen = len(usableLine)  
    section = usableLine[:3]  
    x = 3  
    sectionList.clear()  
    while x < lineLen:  
        sectionList.append(usableLine[x:x+4])  
        x += 4
    formatDict[section] = sectionList  
for k, v in formatDict.items():  
    print ("for key= ", k, "value =", v)  
formatFileHandle.close()  

【问题讨论】:

    标签: python python-3.x list dictionary


    【解决方案1】:

    你总是清除,然后附加然后插入相同的sectionList,这就是它总是覆盖条目的原因 - 因为你告诉程序它应该这样做。

    永远记住:在 Python 作业中从不复制!

    简单修复

    只需插入一个副本:

    formatDict[section] = sectionList.copy()    # changed here
    

    而不是插入引用:

    formatDict[section] = sectionList  
    

    复杂的修复

    发生了很多事情,您可以通过使用诸如分组之类的子任务功能使其“更好”,还应使用with 打开文件,以便即使发生异常也会自动关闭文件和@应该避免 987654326@ 结束已知的循环。

    我个人会使用这样的代码:

    def groups(seq, width):
        """Group a sequence (seq) into width-sized blocks. The last block may be shorter."""
        length = len(seq)
        for i in range(0, length, width):   # range supports a step argument!
            yield seq[i:i+width]
    
    # Printing the dictionary could be useful in other places as well -> so
    # I also created a function for this.
    def print_dict_line_by_line(dct):  
        """Print dictionary where each key-value pair is on one line."""
        for key, value in dct.items():
            print("for key =", key, "value =", value)
    
    def mytask(filename):
        formatDict = {}
        with open(filename) as formatFileHandle:
            # I don't "strip" each line (remove leading and trailing whitespaces/newlines)
            # but if you need that you could also use:
            # for usableLine in (line.strip() for line in formatFileHandle):
            # instead.
            for usableLine in formatFileHandle:
                section = usableLine[:3]
                sectionList = list(groups(usableLine[3:]))
                formatDict[section] = sectionList
        # upon exiting the "with" scope the file is closed automatically!
        print_dict_line_by_line(formatDict)
    
    if __name__ == '__main__':
        mytask('insert your filename here')
    

    【讨论】:

    • 非常感谢。您的简单修复成功了。我会继续查看您对问题的解释,但我会到达那里!另外,感谢“复杂的修复”。里面有很好的建议供我考虑。
    • @BillMorgan 没问题。请不要忘记accept最有帮助的答案:)
    【解决方案2】:

    您可以通过使用with 语句自动关闭文件并将行的其余部分分成四个一组来简化您的代码,从而避免重复使用单个列表。

    from itertools import islice
    
    with open('somefile') as fin:
        stripped = (line.strip() for line in fin)
        format_dict = {
            line[:3]: list(iter(lambda it=iter(line[3:]): ''.join(islice(it, 4)), '')) 
            for line in stripped
        }
    
    for key, value in format_dict.items():
        print('key=', key, 'value=', value)
    

    【讨论】:

    • 真的吗?你会在你的代码中使用list(iter(lambda it=iter(row[3:]): ''.join(islice(it, 4)), '')) 吗? :)
    • @MSeifert 我会包装它,但这是给读者的练习......(嘿 - 不是吗?:p)
    • 好的,好点 - 我喜欢你在可变默认值下所做的。但是,这可能会在row 处抛出NameError,不是吗?
    • @MSeifert bah...我倾向于将事物称为row,然后认为它在发布时看起来很愚蠢,并将它们重命名为line...很好 - 谢谢。
    猜你喜欢
    • 2022-01-04
    • 2018-12-21
    • 2012-08-10
    • 2016-12-27
    • 2013-09-02
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多