2013-01-13 58 views
1

我想要的是能夠處理具有固定鍵集的數據集。所有的鍵都是字符串。數據將永遠不會被編輯。我知道這與正常類型的字典來完成,像這樣:存儲固定密鑰的最佳方式:通過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?

+0

一個正交的建議,你看過[pandas](http://pandas.pydata.org/)嗎? – tacaswell

+0

會不會有一些像memcache那樣的k/v存儲會更好? –

回答

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__

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' 
+0

嗯,問題是要檢索的值可能會有所不同,所以不是實際輸入'key1',而是一個存儲鍵(這是一個字符串)的變量。所以getattr()是必要的。可能是我的錯誤,不能在示例中顯示。除非可以編輯namedtuple的'__getitem__'方法嗎? – Eric

+0

@Eric'__getitem__'已經爲'namedtuple'做了一個理智的事情,其行爲與常規元組一樣(參見文檔中的示例)。但是你可以繼承它,並調用'getattr'來代替。不過,保存你輸入幾個字符是一個很有爭議的理由。 –

+0

與字典相比,namedtuple的內存佔用量是多少? –