暂时修改dict的python配方

时间:2014-08-28 16:36:13

标签: python

我在一些代码中看到了这种模式,我正在写

e = {...} # a dictionary
e["table"] = "users"
e["timestamp"] = time.time()
queue.push(e)
del e["table"]
del e["timestamp"]
[...]
e["table"] = "events"
queue2.push(e)
del e["table"]
# etc..

我在一些队列上解复用一个事件,但每个队列的格式略有不同。我已经开始这样做了:

queue.push( dict(e.items() + [("table":"users"), ("timestamp", time.time())]) )

但它看起来很难看,它会减慢代码速度。我还能做什么?

5 个答案:

答案 0 :(得分:3)

假设queue.push只需要读取权限,您可以尝试这样的事情:

class MergedDicts(dict):
    def __init__(self, *dicts, **kw):
        self.dicts = dicts + (kw,)

    def __getitem__(self, key):
        for d in self.dicts:
            if key in d: return d[key]
        raise KeyError(key)

这将为您提供一个字典,从两个来源返回项目,但避免从原始构建另一个实际副本的开销(您可能需要实现的不仅仅是__getitem__,具体取决于{{1} }需要)。

用法:

push

或:

other = {"table": "users", "timestamp": time.time()}
queue.push(MergedDicts(e, other))

答案 1 :(得分:1)

如果对字典的修改次数与字典本身的大小相比相对较小,则可以通过创建context manager函数并使用它来如图所示,避免每次复制它。这将确保对字典所做的任何更改都是临时的,即使在块中使用它时会抛出异常。

from contextlib import contextmanager

@contextmanager
def contextdict(adict, **kwargs):
    # modify dictionary
    changed = {}
    added = []
    for key in kwargs:
        if key in adict:
            changed[key] = adict[key]
        else:
            added.append(key)
        adict[key] = kwargs[key]
    yield adict
    # restore dictionary
    adict.update(changed)
    for key in added:
        del adict[key]

e = dict(...)  # some dictionary

with contextdict(e, table="users", timestamp=time.time()) as context:
    queue.push(context)
with contextdict(e, table="events") as context:
    queue.push(context)

# e will be unchanged at this point

答案 2 :(得分:0)

您可以使用所需的新字段创建新字典,并在其上使用dict.update和基本字段

e = {...} # a dictionary
d={"table":"users", "timestamp":time.time()}
d.update(e)
queue.push(d)

您还可以使用字段作为列表创建新的dict:

e = {...} # a dictionary
queue.push( e.items() + [("table","users"), ("timestamp",time.time())] )

如果你在大型词典上做了很多,并且不想创建副本,你可以使用Context Manager暂时修改字典,自动完成你现在正在做的事情。


另一个选项,而不是上下文管理器,是在函数中执行修改,将您想要执行的操作作为函数传递:

def modify_dict_and_call( d, newfields, f):
    for k,v in newfields.items():
        d[k]=v
    f(d)
    for k in newfields:
        del d[k]

e = {...} # a dictionary
modify_dict_and_call( e, {"table":"users", "timestamp":time.time()}, queue.push )

答案 3 :(得分:0)

如果您最初只使用每个用例共有的键定义e,则可以使用mock库。 mock.patch.dict允许您临时将字符串添加到字典中(在with语句的持续时间内),但您无法暂时删除键。

e = { ... }
with mock.patch.dict(e, table="users", timestamp=time.time()):
    queue.push(e)

with mock.patch.dict(e, table="events"):
    queue2.push(e)

mock是Python 2.x的第三方模块,在Python 3.4之前,它已作为unittest.mock添加到标准库中。

答案 4 :(得分:0)

我认为它可能会被下一个代码覆盖:

a = {'val': 2, 'val2': -5, "name": 'Vladimir'}
b = {"asdf": 1, "b2": 2}
queue.push( dict( **a, **b) )