具有基于属性的随机访问的对象集合的Python数据结构

4 python

我需要一组对象,这些对象可以通过每个对象共有的某个(唯一)属性进行查找.现在我正在使用一个dicitionary将字典键分配给属性.这是我现在拥有的一个例子:

class Item():
    def __init__(self, uniq_key, title=None):
        self.key = uniq_key
        self.title = title

item_instance_1 = Item("unique_key1", title="foo")
item_instance_2 = Item("unique_key3", title="foo")
item_instance_3 = Item("unique_key2", title="foo")

item_collection = {
        item_instance_1.key: item_instance_1,
        item_instance_2.key: item_instance_2,
        item_instance_3.key: item_instance_3
        }

item_instance_1.key = "new_key"
Run Code Online (Sandbox Code Playgroud)

现在这似乎是一个相当麻烦的解决方案,因为密钥不是对属性的引用,而是在赋值时获取key-attribute的值,这意味着:

  • 字典的键复制已经以对象属性和形式存在的信息
  • 当对象属性被更改时,字典键不会更新.

使用列表并迭代对象似乎效率更低.

那么,对于这种特殊情况,是否有比dict更合适的数据结构,一组对象给我随机访问基于某个对象属性?

这需要与Python 2.4一起使用,因为这就是我所困扰的(在工作中).

如果不是很明显,我是Python的新手.

Ale*_*lli 5

实际上,您不必担心重复信息:dict的键和对象的.key属性只是对完全相同对象的两个引用.

唯一真正的问题是"如果.key重新分配会怎么样".那么,显然你必须使用一个属性来更新所有相关的dicts以及实例的属性; 所以每个对象必须知道它可以被注册的所有序列.理想情况下,人们可能希望为此目的使用弱引用,以避免循环依赖,但是,唉,您不能将weakref.ref(或代理)带到dict.所以,我在这里使用普通引用(替代方法不是使用dict实例,而是使用一些特殊的子类 - 不方便).

def enregister(d, obj):
  obj.ds.append(d)
  d[obj.key] = obj

class Item(object):
    def __init__(self, uniq_key, title=None):
        self._key = uniq_key
        self.title = title
        self.ds = []

    def adjust_key(self, newkey):
        newds = [d for d in self.ds if self._key in d]
        for d in newds:
          del d[self._key]
          d[newkey] = self
        self.ds = newds
        self._key = newkey

    def get_key(self):
        return self._key

    key = property(get_key, adjust_key)
Run Code Online (Sandbox Code Playgroud)

编辑:如果你想要一个包含Item的所有实例的单个集合,那就更容易了,因为你可以使集合成为一个类级属性; 事实上它可以是一个WeakValueDictionary,以避免错误地保持项目存活,如果这是你需要的.即:

class Item(object):

    all = weakref.WeakValueDictionary()

    def __init__(self, uniq_key, title=None):
        self._key = uniq_key
        self.title = title
        # here, if needed, you could check that the key
        # is not ALREADY present in self.all
        self.all[self._key] = self

    def adjust_key(self, newkey):
        # "key non-uniqueness" could be checked here too
        del self.all[self._key]
        self.all[newkey] = self
        self._key = newkey

    def get_key(self):
        return self._key

    key = property(get_key, adjust_key)
Run Code Online (Sandbox Code Playgroud)

现在你可以使用Item.all['akey'],Item.all.get('akey'),for akey in Item.all:,等等-类型的字典所有丰富功能.