2012-03-20 12 views
5

たとえば、私はdictsまたは配列のdictを持っていますが、私は2つのレベルの深さに "深い"コピーをしたいだけですこれを行う簡単な方法はありますか?Pythonでは、どのように特定の深さにdictの深いコピーを行うでしょうか?

私が使用できるライブラリがあるかどうか、または例が見つかりましたが、何も見つかりませんでした。私はかなりPythonに新しいですか、そうでなければ、私は自分自身でこれを行うサブルーチンを書くでしょう。何か案は?コードスニペットは、それを行う方法の説明だけでなく、私が理解するのが速いので、評価されるでしょう。

ありがとうございました。

ADDITIONAL INFO:

私はこれをしたいと思う理由はいくつかは聞いている私はいくつかの値を変更するつもりですし、私は、元は変更したくないとして、私はコピー(ない参照が必要)辞書からの項目のいくつかが、辞書はdictsの(多くの辞書)巨大ですので、私は私のメモリフットプリントを爆破したくない

MY CODE SO FAR

のさて、私は与えますアップ。これは私が予想していたよりも難しく、私はそれを理解する時間がありません。いくつかのデバッグ/テストコードで私の最近の試み。

# 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を通して読んできましたが、それを理解しようとしましたが、私のテストケースではソリューションのどれもうまくいかなかったようです。

私はディクテーション全体を深くコピーし、後でソリューションを最適化しようとします。あなたが本当にハックするのでない限り、これは一種の「plzは私にTEH codzを与える」のように聞こえる

+3

これを行うことでどのような問題を解決したいですか? –

+1

あなたは明白な 'copy.deepcopy(x)'と 'pickle'を試しましたか? – zenpoy

+0

@zenpoy私はcopy.deepcopy(x)を見ましたが、そのコピーを特定の深さに制限できないようです。私はピックルを使用するとは思わなかったし、それはどういう仕組みかわからないけど、あなたの提案は、あなたが深さを指定できるようにコピーをするためにpprintを得ることができると思ったのだろうか?私はそれがどのように動作するか考えなければならない。 – stephenmm

答えて

3

おかげで... ...いずれにせよ

は、カスタムメソッドをする必要がありますサブクラスを持つiterablesの機能擬似コード:我々は深さが不足している場合、私たちは直接、残りの部分をコピーするので、それは、あるとして

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

これは、iterableであるが最大深度に達している場合、アイテムをすべて一緒に追加するのをスキップします。最大深度を超えてネストされた辞書をコピーすることは、私たちがやりたくないものです。 –

+0

ですが、最大深度に達した場合はアイテムをスキップしています。あなたのコードは基本的にcopy = original.copy()と同じです。 –

+0

いいえ、上のvalでコピーしている間、基本的に最大深度以下でrefでコピーします。 –