Python:从集中检索项目
问题内容:
通常,Python集似乎并不是为通过键检索项目而设计的。显然,这就是字典的作用。但是无论如何,给定一个键,您是否可以从一个等于该键的集合中检索一个实例?
同样,我知道这正是字典的用途,但据我所知,有合理的理由要使用一组字典。假设您有一个定义如下的类:
class Person:
def __init__(self, firstname, lastname, age):
self.firstname = firstname
self.lastname = lastname
self.age = age
现在,假设我将要创建大量Person
对象,并且每次创建Person
对象时,我都需要确保它不是先前Person
对象的副本。如果A具有相同的值,Person
则认为A是另一个的重复项,而与其他实例变量无关。因此,自然而然的事情就是将所有对象插入到一个集合中,并定义一个and方法,以便将它们的对象进行比较。Person``firstname``Person``__hash__``__eq__``Person``firstname
另一种选择是创建Person
对象字典,并使用单独创建的firstname
字符串作为键。这里的缺点是我将复制firstname
字符串。在大多数情况下,这并不是真正的问题,但是如果我有10,000,000个Person
对象怎么办?冗余字符串存储实际上可以开始增加内存使用量。
但是,如果两个Person
对象比较相等,则我需要能够检索原始对象,以便firstname
可以按业务逻辑所需的方式合并其他实例变量(除之外)。这使我回到问题所在:我需要某种方法来从中检索实例set
。
反正有这样做吗?还是在这里使用字典是唯一的选择?
问题答案:
我肯定会在这里用字典。将firstname
实例变量重新用作字典键不会复制它-字典将仅使用同一对象。我怀疑字典将比集合使用更多的内存。
要实际节省内存,__slots__
请在类中添加一个属性。这将防止每次10,000,000实例从具有__dict__
属性,这将节省更多的内存比的潜在开销dict
过set
。
编辑 :一些数字来支持我的主张。我定义了一个愚蠢的示例类,存储了成对的随机字符串:
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__
。