2015-06-22 199 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的东西之一...... –

相关问题