Python列表,查找对象名称,效率建议

3 投票
2 回答
514 浏览
提问于 2025-04-16 01:46

假设我有一个这样的对象:

class Foo(object):
  def __init__(self, name=None):
    self.name = name

  def __repr__(self):
    return self.name

还有一个包含多个实例的列表,比如:

list = [Foo(name='alice'), Foo(name='bob'), Foo(name='charlie')]

如果我想找到一个特定名字的对象,我可以使用以下方法:

def get_by_name(name, list):
  return [foo for foo in list if foo.name == name][-1]

这显然意味着:

print get_by_name('alice', list)
>> alice

不过,有没有更高效的数据结构或方法来获取这些对象呢?实际上,这些对象的名字只有在运行时才能知道,并且在对象的生命周期中可能会发生变化。

有什么建议吗?

更新:

感谢Matt Joiner的回答,我已经更新了代码,以支持多个同名的Foo对象:

class Foo(object):
    _all_names = {}    
    def __init__(self, name=None):
        self._name = None
        self.name = name        
    @property
    def name(self):
        return self._name        
    @name.setter
    def name(self, name):
        if self._name is not None:
            self._all_names[self._name].remove(self)
        self._name = name
        if name is not None:
            self._all_names.setdefault(name, []).append(self)
    @classmethod
    def get_by_name(cls, name):
        return cls._all_names[name]        
    def __repr__(self):
        return "{0}".format(self.name)

l = [Foo("alice"), Foo("bob"), Foo('alice'), Foo('charlie')]
print Foo.get_by_name("alice")
print Foo.get_by_name("charlie")

对这种方法有什么看法吗?

2 个回答

1

这个情况有点让人困惑。

你要在一个列表中寻找这个对象,而列表是一种线性的数据结构。也就是说,你只能一个一个地查看,这样的话,所需的时间就会随着列表的长度线性增长。所以,这就是你速度慢的原因。

要提高速度,可以使用某种哈希方案,这样你就可以通过你感兴趣的键(在你的例子中是name)直接找到对象。这就像在字典中查找键一样,查找的时间是固定的。这基本上就是Matt的回答所做的。他保持一个“索引”,作为类级别的结构,这样你就可以通过哈希查找,而不是一个一个地遍历列表。

8

试试这个:

class Foo(object):
    _all_names = {}
    def __init__(self, name=None):
        self.name = name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, name):
        self._name = name
        self._all_names[name] = self
    @classmethod
    def get_by_name(cls, name):
        return cls._all_names[name]
    def __str__(self):
        return "Foo({0})".format(self.name)

a = Foo("alice")
b = Foo("bob")
print Foo.get_by_name("alice")

请记住,这个例子很简单,主要是为了传达一个概念。其实你可以在这里做很多调整和检查。

撰写回答