2014-08-28 65 views
0

我看到一些代碼,這種模式暫時修改字典蟒蛇的食譜,我正在寫在飛行

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

但它看起來很醜,它會減慢代碼。我還可以做些什麼?

回答

0

您可以創建你想要的新領域一個新的字典,它使用dict.update與基礎領域

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

你也可以創建一個新的字典與作爲列表字段:

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

如果你這個做大型辭書了很多,不希望創建一個副本,Y您可以使用暫時修改字典的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

假設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) 

這會給你一個從兩個來源返回項目的字典,但避免構建另一個實體的開銷l從原件複製(您可能需要執行的不僅僅是__getitem__,具體取決於push的需要)。

用法:

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

或:

queue.push(MergedDicts(e, table="users", timestamp=time.time())) 
+0

漂亮,乾淨的解決方案。我看到的唯一可能的缺點是它會使元素訪問速度變慢。 OTOH,如果沒有很多的訪問和字段更新的數量大 – goncalopp 2014-08-28 17:06:00

+0

不'MergeDicts'需要調用其超在自己的'__init __()'這可能有更好的表現?否則,它不是一個正確初始化子... – martineau 2014-08-28 17:36:06

+0

'MergedDicts'似乎並沒有採取的事實,這本身就是一個'dict'優勢;所有的工作都是由新的'dicts'屬性完成的。 – chepner 2014-08-28 17:44:26

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第三方模塊。

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