为不存在的对象属性赋值

Assigning values to objects attributes that don't exist

我正在使用 python(2.7) 进行数据挖掘作业。我为所有单词(类别中存在的单词)创建了一个权重字典,对于这个字典中不存在的单词,我想分配一个默认值。 首先我在使用它之前尝试为每个键设置默认值,它工作得很好,但不知何故我认为它看起来不那么 pythonic。因此我尝试使用 defaultdict,它在大多数情况下工作得很好。但是,有时它 returns 是一个不正确的值。一开始我以为可能是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) 快吗

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)

显然,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 中的工作原理。

这不是 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]

应该returnvar=2的当前值。它在初始化时没有被替换到字典中,但表现得就像你在这个位置定义了一个函数,访问 "outer" 变量 var.

黑客是这样的:

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

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

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

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