我有以下代码:

import json
stats = dict()
for line in input :  # many many lines
    for (field,value) in json.loads(line).iteritems() :
        stats.get(field,very_expensive_initializer(field)).add(value)


问题在于Python并不懒惰,因此对于每行中的每个字段都调用一次very_expensive_initializer,而不是为每个字段调用一次。对?

避免这种情况的正确方法是什么?

例如,这足够惯用吗?

try :  s = stats[field]
except KeyError : s = stats[field] = very_expensive_initializer(field)
s.add(value)

最佳答案

如果默认值昂贵,请测试密钥:

item = stats.get(field) or very_expensive_initializer(field)
item.add(value)


或者stats[field]可能为空:

item = stats[field] if field in stats else very_expensive_initializer(field)
item.add(value)


or和条件表达式的计算都比较延迟。

您仍然可以将其设置为单线,但是我不确定您应该这样做。上面的代码与您的原始代码匹配。

请注意,这不会将very_expensive_initializer(field)添加到stats!您也可以这样做:

if field not in stats:
    stats[field] = very_expensive_initializer(field)


要么

try:
    item = stats[field]
except KeyError:
    item = stats[field] = very_expensive_initializer(field)


如果通常在field中找不到stats,则选择第一个;如果偶尔仅在field中找不到stats,则选择后者。

您的下一个选择是dict的子类并添加__missing__方法:

class subclassed_dict(dict):
    def __missing__(self, key):
        item = self[key] = very_expensive_initializer(key)
        return item


然后将其用作stats

stats = subclassed_dict()


每当您尝试访问尚不存在的密钥时,Python都会调用__missing__

演示:

>>> def very_expensive_initializer(field):
...     print 'Doing loads of work'
...     return set()
...
>>> class subclassed_dict(dict):
...     def __missing__(self, key):
...         item = self[key] = very_expensive_initializer(key)
...         return item
...
>>> stats = subclassed_dict()
>>> stats['foo'].add(2)
Doing loads of work
>>> stats['foo'].add(3)
>>> stats['foo'].add(4)
>>> stats['bar']
Doing loads of work
set([])
>>> stats['bar']
set([])

关于python - 如何在字典中初始化值?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20379435/

10-13 07:26