2012-03-20 62 views
5

例如,如果我有一個字典的字典或字典的字典,但我只希望「深」複製到兩個層次的深度是否有一個簡單的方法來做到這一點?在python中,我將如何對特定深度的字典進行深層複製?

我四處張望,看看是否有我可以使用的庫或示例,但找不到任何東西。我對Python相當陌生,否則我會自己編寫子例程來完成這個任務。有任何想法嗎?代碼片段將不勝感激,因爲它可以讓我更快地理解,而不僅僅是解釋如何去做。

謝謝。

附加信息:

有些人問我爲什麼會想這樣做,我需要一個副本(而不是裁判,因爲我要修改一些值,我不希望原始修改)的一些從字典中的項目,但該字典是巨大的(類型的字典中許多字典),所以我並不想炸掉我的內存佔用

到目前爲止我的代碼

好吧,我給向上。這比我預期的要困難得多,我沒有時間弄清楚。我最近嘗試了一些調試/測試代碼。

# Deep copy any iteratable item to a max depth and defaults to removing the 
# rest. If you want to keep the stuff past max depth as references to orig 
# pass the argument else_ref=1. Ex: 
# dict_copy = copy_to_depth(dict_orig, 2, else_ref=1) 
def copy_to_depth(orig, depth, **kwargs): 
    copy = type(orig)() 
    for key in orig: 
    # Cannot find a reliable and consistent way to determine if the item 
    # is iterable. 
    #print orig[key].__class__ 
    #if hasattr(orig[key], '__iter__'): 
    #if hasattr(orig[key], '__contains__'): 
    #if iterable(orig[key]): 
    #try: 
    if hasattr(orig[key], '__contains__'): 
     if depth > 0: 
     copy[key] = copy_to_depth(orig[key], depth - 1, **kwargs) 
     else: 
     if 'else_ref' in kwargs: 
      copy[key] = orig[key] 
     else: 
      copy[key] = 'PAST_MAX_DPETH_ITERABLE_REMOVED' 
    #except: 
    else: 
     copy[key] = orig[key] 
    return copy 

def iterable(a): 
    try: 
     (x for x in a) 
     return True 
    except TypeError: 
     return False 

people = {'rebecca': 34, 'dave': 'NA', 'john': 18, 'arr': [9,8,{'a':1,'b':[1,2]}], 'lvl1': 
    {'arr': [9,8,{'a':1,'b':[1,2]}], 'dave': 'NA', 'john': 18, 'rebecca': 34, 'lvl2': 
    {'arr': [9,8,{'a':1,'b':[1,2]}], 'dave': 'NA', 'john': 18, 'rebecca': 34, 'lvl3': 
     {'rebecca': 34, 'dave': 'NA', 'john': 18, 'arr': [9,8,{'a':1,'b':[1,2]}]}}}} 
print people 


ppl_cpy = copy_to_depth(people, 1) 

ppl_cpy['arr'][1] = 'nine'     # does not mod orig 
ppl_cpy['john'] = 0     # does not mod orig 
ppl_cpy['lvl1']['john'] = 1   # does not mod orig b/c copy_to_depth 
ppl_cpy['arr'][3]['a'] = 'aie'  # does not mod orig 
#ppl_cpy['lvl1']['lvl2']['john'] = 2 # Rest cause an error 
#ppl_cpy['lvl1']['lvl2']['lvl3']['john'] = 3 
print people 
print ppl_cpy 

ppl_cpy = copy_to_depth(people, 1, else_ref=1) 
ppl_cpy['john'] = 0     # does not mod orig 
ppl_cpy['lvl1']['john'] = 1   # does not mod orig b/c copy_to_depth was 1 
ppl_cpy['lvl1']['lvl2']['john'] = 2 # Rest Do not cause error but modifies orig 
ppl_cpy['lvl1']['lvl2']['lvl3']['john'] = 3 
print people 
print ppl_cpy 

I無法找到可靠且一致的方式來確定該項是否可迭代。我一直在閱讀this post,並試圖找出答案,但沒有任何解決方案似乎適用於我的測試案例。

我會深入複製整個字典,並嘗試稍後(或不是)優化解決方案。

謝謝...

+3

你希望通過這樣做來解決什麼問題? – 2012-03-20 20:58:34

+1

你是否嘗試過明顯的'copy.deepcopy(x)'和'pickle'? – zenpoy 2012-03-20 21:08:00

+0

@zenpoy我看過copy.deepcopy(x),但它似乎沒有能力將其副本限制到特定深度。我沒有想到使用泡菜,我不知道如何工作,但你的建議讓我想,也許你可以得到pprint做的副本,因爲它確實讓你指定一個深度?我必須考慮如何這將工作。 – stephenmm 2012-03-20 21:25:53

回答

3

這聽起來有點像「PLZ給我格蘭codz」 ......

在任何情況下,你需要一個自定義的方法,除非你真的想破解了具有子類的迭代的功能。僞代碼:

def copy_to_depth(original, depth) 
    copy = type(original)() 
    for item in original 
     if item is iterable and depth > 0 
      copy + copy_to_depth(item, depth - 1) 
     else 
      copy + item 
    return copy 
1

其實,前面的例子就只是複製任何字典,因爲它是,因爲如果我們用完了深入的,我們只是剩餘部分直接複製。正確的版本將是:

def copy_to_depth(original, depth) 
    copy = type(original)() 
    for item in original 
     if item is iterable 
      if depth > 0 
       copy + copy_to_depth(item, depth - 1) 
     else 
      copy + item 
    return copy 

有一個微妙的區別。 (不幸的是,我不能評論答案本身)

+0

如果它是可迭代的,但您已經達到最大深度,則這將只跳過添加項目。複製超出最大深度的任何嵌套字典正是我們不想做的。 – 2012-03-20 21:40:45

+0

但是如果我們達到最大深度,則跳過該項目是我們想要做的事,對吧?你的代碼基本上等同於copy = original.copy()。 – 2012-03-20 21:47:58

+0

不,我們希望通過ref複製,基本上,低於最大深度,同時複製上面的val。 – 2012-03-20 21:49:11