繁体   English   中英

Python:从集合中检索项目

[英]Python: Retrieve items from a set

通常,Python集似乎不是为按键检索项而设计的。 这显然是字典的用途。 但是,无论如何,给定一个键,你可以从一个等于键的集合中检索一个实例?

同样,我知道这正是字典的用途,但据我所知,有一些合理的理由想要用字符集来完成。 假设您有一个类定义类似于:

class Person:
   def __init__(self, firstname, lastname, age):
      self.firstname = firstname
      self.lastname = lastname
      self.age = age

现在,假设我要创建大量的Person对象,每次创建Person对象时,我都需要确保它不是前一个Person对象的副本。 如果Person具有相同的firstname ,则被视为另一个Person的副本,而不管其他实例变量如何。 很自然地,显而易见的事情是将所有Person对象插入到一个集合中,并定义一个__hash____eq__方法,以便通过它们的firstname来比较Person对象。

另一种选择是创建Person对象的字典,并使用单独创建的firstname字符串作为键。 这里的缺点是我要复制firstname字符串。 在大多数情况下,这不是一个真正的问题,但如果我有10,000,000个Person对象怎么办? 冗余字符串存储可能真的开始在内存使用方面加起来。

但是如果两个Person对象的比较相同,我需要能够检索原始对象,以便可以按业务逻辑所需的方式合并其他实例变量(除了firstname )。 这让我回到了我的问题:我需要一些方法来从一个set检索实例。

反正有没有这样做? 或者使用字典是唯一真正的选择?

我肯定会在这里使用字典。 firstname实例变量重用为字典键不会复制它 - 字典将只使用相同的对象。 我怀疑字典会比集合使用更多的内存。

要实际保存内存,请在类中添加__slots__属性。 这将阻止每个10,000,000个实例具有__dict__属性,这将比一个set上的dict的潜在开销节省更多的内存。

编辑 :一些数字支持我的说法。 我定义了一个存储随机字符串对的愚蠢示例类:

def rand_str():
    return str.join("", (chr(random.randrange(97, 123))
                         for i in range(random.randrange(3, 16))))

class A(object):
    def __init__(self):
        self.x = rand_str()
        self.y = rand_str()
    def __hash__(self):
        return hash(self.x)
    def __eq__(self, other):
        return self.x == other.x

此类的一组1,000,000个实例使用的内存量

random.seed(42)
s = set(A() for i in xrange(1000000))

在我的机器240 MB。 如果我加

    __slots__ = ("x", "y")

在课堂上,这个数字下降到112 MB。 如果我将相同的数据存储在字典中

def key_value():
    a = A()
    return a.x, a

random.seed(42)
d = dict(key_value() for i in xrange(1000000))

这使用249 MB没有__slots__和121 MB使用__slots__

是的,你可以这样做:一个set可以迭代。 但请注意,这是一个O(n)操作,而不是dict的O(1)操作。

所以,你必须权衡速度记忆 这是经典之作。 我个人会在这里进行优化(即使用字典),因为内存不会如此快速地缩短,只有10,000,000个对象并且使用字典非常容易。

至于firstname字符串的额外内存消耗:由于字符串在Python中是不可变的,因此将firstname属性指定为键不会创建新字符串,而只是复制引用。

我想你会在这里得到答案:

在Python中超越工厂

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM