存储固定密钥的最佳方式:通过python中的密钥访问的值数据集?
我想要的是能够处理具有固定键集的数据集。所有的键都是字符串。数据将永远不会被编辑。我知道这与正常类型的字典来完成,像这样:存储固定密钥的最佳方式:通过python中的密钥访问的值数据集?
data_a = {'key1': 'data1a', 'key2': 'data2a', 'key3': 'data3a'}
data_b = {'key1': 'data1b', 'key2': 'data2b', 'key3': 'data3b'}
data_c = {'key1': 'data1c', 'key2': 'data2c', 'key3': 'data3c'}
他们必须能够被称为像这样:
data_a['key1'] # Returns 'data1a'
然而,这看起来是浪费内存(因为字典明显保持自己三分之一空或类似的东西,同时也存储密钥多次),也很繁琐的创建,因为我需要不断地在我的代码中一遍又一遍地输入相同的密钥。我也冒着意外改变数据集中的某些东西的风险。
我现在的解决方案是首先将一组键存储在一个元组中,然后将数据作为元组存储起来。它看起来像这样:
keys = ('key1', 'key2', 'key3')
data_a = ('data1a', 'data2a', 'data3a')
data_b = ('data1b', 'data2b', 'data3b')
data_c = ('data1b', 'data2c', 'data3c')
检索数据,我这样做:
data_a[keys.index('key1')] # Returns 'data1a'
然后,我了解到这似乎是能够做什么,我需要这个东西叫做namedtuples:
import collections
Data = collections.namedtuple('Data', ('key1', 'key2', 'key3'))
data_a = Data('data1a', 'data2a', 'data3a')
data_b = Data('data1b', 'data2b', 'data3b')
data_c = Data('data1b', 'data2c', 'data3c')
但是,看起来我不能简单地通过键调用值。相反,以获取由关键数据,我必须使用GETATTR,这似乎不是很直观:
getattr(data_a,'key1') # Returns 'data1a'
我的标准是记忆效率,然后再执行效率。在这三种方法中,哪种方法可以做到最好?或者我错过了一些东西,还有更多的pythonic成语来得到我想要的东西?
编辑:我现在最近也了解到__slots__
的存在,它显然运行更高效的键:值对,而非常消耗相同(?)的内存量。与this类似的实现是否可以替代namedtuples?
是,__slots__
应该做的:它是否会改变时才需要。
class Data:
__slots__ = ["key1", "key2"]
def __init__(self, k1, k2):
self.key1, self.key2 = k1, k2
def __getitem__(self, key):
if key not in self.__slots__:
raise KeyError("%r not found" % key)
return getattr(self, key)
让我们尝试了这一点:
>>> Data(1, 2)["key1"]
1
上key not in self.__slots__
的条件是一个全面的检查;如果它不存在,getattr
会很乐意为我们提取__init__
。
namedtuple
似乎是正确的使用。如果你的“钥匙”是固定的,你不需要getattr
并且可以使用正常的语法检索对象的属性:
In [1]: %paste
import collections
Data = collections.namedtuple('Data', ('key1', 'key2', 'key3'))
data_a = Data('data1a', 'data2a', 'data3a')
data_b = Data('data1b', 'data2b', 'data3b')
data_c = Data('data1b', 'data2c', 'data3c')
## -- End pasted text --
In [2]: data_a.key1
Out[2]: 'data1a'
这种用法也证明文档:
>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
Point(x=11, y=22)
你如果第二个参数(属性名称)是常量,通常不会使用getattr
。
In [3]: attr = input('Attribute: ')
Attribute: key3
In [4]: getattr(data_b, attr)
Out[4]: 'data3b'
嗯,问题是要检索的值可能会有所不同,所以不是实际输入'key1',而是一个存储键(这是一个字符串)的变量。所以getattr()是必要的。可能是我的错误,不能在示例中显示。除非可以编辑namedtuple的'__getitem__'方法吗? – Eric
@Eric'__getitem__'已经为'namedtuple'做了一个理智的事情,其行为与常规元组一样(参见文档中的示例)。但是你可以继承它,并调用'getattr'来代替。不过,保存你输入几个字符是一个很有争议的理由。 –
与字典相比,namedtuple的内存占用量是多少? –
一个正交的建议,你看过[pandas](http://pandas.pydata.org/)吗? – tacaswell
会不会有一些像memcache那样的k/v存储会更好? –