将字典作为列表访问

5 投票
4 回答
750 浏览
提问于 2025-04-16 20:01

我有一个数据源,最适合用字典来表示(它实际上是一个由键=值对组成的集合)。为了特定的可视化目的,我需要提供一种像列表一样的数据访问方式(除了常规的字典访问方式),这意味着你应该能够做到以下几点:

data["mykey"] # returns the associated value
data[12][0] # returns the 13th key in the dictionary
data[12][1] # returns the 13th value in the dictionary

我找不到合适的外观实现——如果我把索引当作字典的键来存储:

data[12] = ("mykey", "myval")

我可以很容易地解决最后两个情况,但我失去了处理第一个情况的能力。如果我像这样存储数据:

data["mykey"] = "myval"

我必须先把所有的键和值列举到一个临时列表中,然后才能返回元素。

请注意,所有这些实现都假设我使用的是一个OrderedDict(有序字典)。

你会如何同时提供这两种接口呢?

如果你感兴趣,这个问题是为了创建一个PyQt的QAbstractTableModel,而底层的数据容器是一个字典。

谢谢。

4 个回答

0

一个dict的子类可以尝试通过索引来访问键,但如果失败的话就会转而使用默认的键访问方式,这样可能就能解决问题。大概是这样的:

from collections import OrderedDict

class IndexableDict(OrderedDict):
    def __getitem__(self, key):
        """Attempt to return based on index, else try key"""
        try:
            _key = self.keys()[key]
            return (_key, super(IndexableDict, self).__getitem__(_key))
        except (IndexError, TypeError):
            return super(IndexableDict, self).__getitem__(key)

d = IndexableDict(spam='eggs', messiah=False)
d['messiah'] ## False
d[1] ## ('messiah', False)
d[0] ## ('spam', 'eggs')

编辑:如果你用整数作为键,这个方法就会出问题。

1

list(data.items())[12] 这个代码会返回你在 OrderedDict 中第13个键值对的一个 (key, value) 元组。list(data.keys())[12] 则只会返回第13个键,而 list(data.values())[12] 会返回第13个值。

不过,对于很大的 dict 来说,这样做可能不是个好主意,因为每次都会重新创建这个列表。

(不过,这正是 OrderedDict 在它的 __repr__ 方法中使用的同样方法:return '%s(%r)' % (self.__class__.__name__, list(self.items()))

3

我需要做同样的事情,把数据放在一个列表控件(ListCtrl)里,有时候我需要通过键来访问数据,而不是通过索引(这样就不用每次都去搜索一个任意值)。如果你有一个字典的列表,我找到的最好方法是创建另一个字典,里面存放的是同样的项目,但可以通过键来访问。这就是我在加载数据时的方法:

  def SetData(self, cols, data):
    for idx, row in enumerate(data):
      item = dict((k, v.rstrip() if hasattr(v, 'rstrip') else v) for k, v in zip(cols, row))

      self.data[idx] = item

      self.byid[row[0]] = item

所以我在自定义的对象里有一个字典的列表,保存在self.data里,然后还有一个字典保存在self.byid里,这个字典里存放的是相同的项目,但可以通过ID列(在我的行中是第0列)来访问。当我需要更新数据时,只要我有一个ID,我就可以用self.byid[id][field] = newval来更新。因为在Python中,所有东西都是指针(引用),所以在self.byid里改变字典的值,会在self.data里的字典列表中反映出来。这种方法非常有效。

撰写回答