我想要的是能够处理具有固定密钥集的数据集。所有键都是字符串。永远不会编辑数据。我知道这可以用正常的dicts来完成,如下:
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'
然而,这看起来是浪费内存(因为字典显然保持自己1/3空或类似的东西,同时还存储了多次键),并且因为我需要继续输入也很乏味在我的代码中一遍又一遍地使用相同的密钥。我还冒着意外更改数据集中某些内容的风险。
我目前的解决方案是首先将一组密钥存储在元组中,然后将数据存储为元组。它看起来像这样:
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的实现是否适合替代命名元组?
答案 0 :(得分:1)
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'
答案 1 :(得分:1)
是的,__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__
。