将值分配给不存在的对象属性

时间:2015-06-22 00:55:23

标签: python defaultdict

我正在使用python(2.7)进行数据挖掘作业。我为所有单词(存在于类别中)创建了一个权重dict,对于此dict中不存在的单词,我创建了,我想指定一个默认值。 首先我在使用它之前尝试使用setdefault for everykey,它工作得很好,但不知怎的,我觉得它看起来并不那么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 每次使用setdefault(k,v)更快

3 个答案:

答案 0 :(得分:1)

这不是defaultdict的用例。

相反,只需使用get从字典中获取值。

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

是完全可以接受的python" get"有第二个参数,如果找不到键,则为默认值。

如果您只需要#34; get&#34 ;,则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 的当前值。它在初始化时没有被代入字典,但表现得好像你已经在这个位置定义了一个函数,访问了"外部"变量变种

黑客就是这样:

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

现在constfunc在初始化时被计算,x是调用的局部变量,而lambda现在将返回一个不再变化的x。我想你可以内联这个(未经测试):

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

看,Python的魔力,捕获"关闭"假装进行函数式编程的命令式语言的异常。

答案 1 :(得分: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)

答案 2 :(得分: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中是如何工作的。