2015-06-22 193 views
0

我正在用python(2.7)做一個數據挖掘作業。我爲所有單詞(存在於類別中)創建了一個權重詞典,並且表示在該詞典中不存在的單詞,我想指定默認值。 首先,我在每次使用setdefault之前嘗試過,它完美地工作,但不知何故,我認爲它看起來並不那麼pythonic。因此,我嘗試使用defaultdict,大多數情況下工作得很好。但是,有時會返回不正確的值。首先,我認爲這可能是由defaultdict或lambda函數引起的,但顯然沒有錯誤。將值賦給不存在的對象屬性

for node in globalTreeRoot.traverse(): 
    ...irrelevant... 
    weight_dict = {.......} 
    default_value = 1.0/(totalwords + dictlen) 
    node.default_value = 1.0/ (totalwords + dictlen) 
    ...... 
    node.weight_dict_ori = weight_dict 
    node.weight_dict = defaultdict(lambda :default_value,weight_dict) 

所以,當我試圖打印一個在循環中不存在的值時,它給了我一個正確的值。但是,代碼完成運行後,當我嘗試:

print node.weight_dict["doesnotexist"], 

它給了我一個不正確的值,當通常不正確相關的一些其他節點的值。我試過搜索python命名系統動態地給對象屬性賦值,但沒搞清楚。

順便提一句,是defaultdict更快存在使用它(K,V)每次

回答

1

這不是defaultdict的使用案例。

相反,只需使用get即可從字典中獲取值。

val = dict.get("doesnotexist", 1234321) 

是完全可以接受的python「get」有第二個參數,如果找不到鍵的話默認值。

如果你只需要這個「get」,defaultdict有點矯枉過正。它的意思是這樣使用:

example = defaultdict(list) 
example[key].append(1) 

而不必每次都明確地初始化密鑰列表組合。對於數值的改進是邊際:

ex1, ex2 = dict, defaultdict(lambda: 0) 
ex1[key] = ex1.get(key, 0) + 1 
ex2[key] += 1 

你原來的問題可能是因爲你重複使用的變量存儲的權重。確保它是本地到循環!

var = 1 
ex3 = defaultdict(lambda: var) 
var = 2 
print ex3[123] 

應該返回var=2當前值。它在初始化時不會被替換到字典中,而是表現得好像您在此位置定義了一個函數,訪問「外部」變量var。

一個黑客是這樣的:

def constfunc(x): 
    return lambda: x 
ex3 = defaultdict(constfunc(var)) 

現在constfunc在初始評估,x是調用的局部變量,和現在的λ將返回其已不改變X。我想你可以內聯這個(未經測試):

ex3 = defaultdict((lambda x: lambda: x)(var)) 

看哪,Python中的魔法,奪取「倒閉潮」的命令式語言假裝做函數式編程的異常。

+0

只是爲了明確的OP,'get'的兩個參數形式允許指定一個默認值,如果指定的鍵不存在於字典中,則返回一個默認值。 –

+0

謝謝!我認爲** get(key,defaultvalue)**正是我所期待的。此外,感謝您解釋「關閉」。我想我誤解了它的變量範圍方法。 –

0

setdefault絕對是你應該用來設置默認值。

for node in globalTreeRoot.traverse(): 
    node.default_value = 1.0/(totalwords + dictlen) 
    node.weight_dict = {} 
    # if you did want to use a defaultdict here for some reason, it would be 
    # node.weight_dict = defaultdict(lambda: node.default_value) 
    for word in wordlist: 
     value = node.weight_dict.setdefault(word, node.default_value) 
+0

實際上,它是** defaultdict(lambda:default_value,weight_dict)**。你必須給它一個字典。我知道它的工作原理,但我試圖弄清楚這裏有什麼問題。 –

+0

@RafaelJ如果你給它一個字典,它會初始化該字典作爲'defaultdict'的一部分。目前還不清楚爲什麼你想這樣做。 'd1 = {'key':'value'}; d2 = defaultdict(lambda:42,d1)'之後'd2 == {'key':'value'}'和'd2 ['new_key']; d2 = {'key':'value','new_key':42}'。 –

0

顯然,defaultdict有問題。

d1 = {"a":10,"b":9,"c":8} 
seven = 7 
d2 = defaultdict(lambda :seven,d1) 
seven = 8 
d3 = defaultdict(lambda :seven,d1) 

而結果:

>>> d2[4234] 
8 

我還是不明白,爲什麼是這樣工作的。至於我的工作,我會堅持setdefault

更新: 感謝您的回答。我誤解了Python中變量範圍的工作原理。

+0

不要設置'seven = 8'。這不是defaultdict,它是行爲不當,但是Python中非直觀的變量範圍以及不恰當的變量重用。 –

+0

甚至很難對變量範圍進行評估。 'lambda:seven'是一個返回變量'seven'的當前值的函數。如果你想本地範圍它,你會有'lambda s = seven:s',這將正常工作。 –

+0

@AdamSmith這是一個醜陋的黑客讓它成爲本地,恕我直言。還有一種行爲,當我想將默認值設置爲一個變量時,也經常傷害到我...變量範圍是我討厭Python的東西之一...... –

相關問題