2

我想要的是能够处理具有一组固定键的数据集。所有的键都是字符串。数据永远不会被编辑。我知道这可以用普通的字典来完成,如下所示:

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'

我的标准首先是内存效率,然后是性能效率。在这 3 种方法中,哪种方法最好?还是我错过了一些东西,并且有一个更pythonic的成语来获得我想要的东西?

编辑:我现在最近也了解到了 的存在__slots__,它显然对 key:value 对运行更有效,同时几乎消耗了相同的(?)内存量。与此类似的实现会是命名元组的合适替代方案吗?

4

2 回答 2

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'
于 2013-01-13T07:29:54.150 回答
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__

于 2013-01-13T10:34:43.397 回答