如何修复使用自定义词典时的键错误

时间:2012-11-24 19:34:01

标签: python dictionary

我正在尝试执行以下操作:解析我的音乐文件夹中的所有文件,如果它们是我的收藏夹,请将它们复制到单独的文件夹中。

为了达到这个目的,我正在用我喜爱的曲目解析一个xml并使用这些信息创建一个像这样的结构的自定义词典

lovedSongs[artist][title] = 1

当我从我的文件夹中解析文件时,我从id3标签中读取歌曲标题和艺术家,理论上,我试着看看lovedSongs[tagArtist][tagTitle]是否为1

for filename in filelist:     
        if filename[-4:] == ".mp3":
            try:
                id3r = id3reader.Reader(filename)
            except UnicodeDecodeError:
                artist = "None"
                title = "None"
            except IOError:
                artist = "None"
                title = "None"
            else:
                artist = ensureutf8andstring(id3r.getValue('performer'))
                title = ensureutf8andstring(id3r.getValue('title'))

            if artist != "None" or title != "None":
                if lovedSongs[artist][title] == 1:
                    print artist + ' - ' + title

当我尝试运行.py文件时,我得到dictionary Key Error。我在这里找到了一个潜在的答案:How to make a python dictionary that returns key for keys missing from the dictionary instead of raising KeyError?并将其应用如下,但我仍然遇到了关键错误

class SongDict(dict):
    def __init__(self, default=None):
        self.default = default

    def __getitem__(self, key):
        if not self.has_key(key):
            self[key] = self.default()
        return dict.__getitem__(self, key)

    def __missing__(self, key):
        return 0

什么是最好的解决方案?使用try / except而不是简单的if?

P.S。我想我应该提到我是python的新手,只有几个小时的“经验”,这是我尝试学习语言的方式。

2 个答案:

答案 0 :(得分:2)

听起来你真正想要的只是一个简单的set

for filename in filelist:     
    if filename.endswith(".mp3"):
        try:
            id3r = id3reader.Reader(filename)
        except (UnicodeDecodeError, IOError):
            pass
        else:
            artist = ensureutf8andstring(id3r.getValue('performer'))
            title = ensureutf8andstring(id3r.getValue('title'))

            if artist != "None" or title != "None":
                if (artist, title) in lovedSongs:
                    print artist + ' - ' + title

答案 1 :(得分:1)

您可以尝试的一件事是使用defaultdict,参数为defaultdict(dict)。无论何时尝试引用不存在的值,它都不会抛出错误,而是返回您指定的默认空值:

In [7]: from collections import defaultdict

In [8]: lovedsongs = defaultdict(lambda: defaultdict(dict))

In [9]: lovedsongs['OAR']['Blackrock'] = 1

In [10]: lovedsongs['Timati']['Moj Put'] = 1

In [11]: lovedsongs
Out[11]: defaultdict(<function <lambda> at 0x24e5ed8>, {'Timati': defaultdict(<type 'dict'>, {'Moj Put': 1}), 'OAR': defaultdict(<type 'dict'>, {'Blackrock': 1})})

In [12]: lovedsongs['Not']['Found']
Out[12]: {}

In [13]: if lovedsongs['Not']['Found'] == 1:
   ....:     print 'Found it'
   ....:
   ....:

In [14]: if lovedsongs['OAR']['Blackrock'] == 1:
   ....:     print 'Found it'
   ....:
   ....:
Found it

通过查看单级(即“更常规”)defaultdict(lambda: defaultdict(dict))如何工作,可以更好地理解defaultdict语法:

In [1]: from collections import defaultdict

In [2]: d = defaultdict(int)

In [3]: d['one'] = 1

In [4]: d['two'] = 2

In [5]: d
Out[5]: defaultdict(<type 'int'>, {'two': 2, 'one': 1})

In [6]: d['one']
Out[6]: 1

In [7]: d['three']
Out[7]: 0

我们使用defaultdict参数声明int - 这意味着如果找不到值,而不是抛出错误,我们只会返回0(因为{ {1}}是整数的空值)。如果我们使用0,我们会返回str,如果我们使用'',我们会收到字典。然而,在这种情况下棘手的部分是你有一个嵌套字典(dict),如果你试图引用嵌套字典中不存在的键,它将遇到同样的问题:

defaultdict(dict)

因此,为了使我们的嵌套字典成为In [13]: d = defaultdict(dict) In [14]: d['three']['more'] --------------------------------------------------------------------------- KeyError Traceback (most recent call last) /path/<ipython console> in <module>() KeyError: 'more' ,我们必须做一些诡计:因为defaultdict的参数需要可调用(但不是然后调用 - &gt;请参阅defaultdictint),我们使用int()函数来模拟此行为。在一个非常简单的层面上,将lambda视为阻止在需要之前调用lambda。现在,您将拥有一个字典(带有嵌套字典),可以处理两层深度的缺失键,而不会抛出错误。希望能解释一下。