如何初始化字典中的值?

时间:2013-12-04 15:33:06

标签: python dictionary initialization

我有以下代码:

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)

3 个答案:

答案 0 :(得分:2)

如果默认值很高,请测试密钥:

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([])

答案 1 :(得分:1)

这里不会使用例外

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

s = stats[field]

答案 2 :(得分:0)

这似乎更适合反序列化器

http://docs.python.org/2/library/json.html#encoders-and-decoders

>>> import json
>>> def as_complex(dct):
...     if '__complex__' in dct:
...         return complex(dct['real'], dct['imag'])
...     return dct
...
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
...     object_hook=as_complex)
(1+2j)
>>> import decimal
>>> json.loads('1.1', parse_float=decimal.Decimal)
Decimal('1.1')