2012-03-20 13 views
5

Ad esempio, se ho un dittico di dict o un dittico di matrici, ma desidero solo copiare "in profondità" a due livelli di profondità, esiste un modo semplice per farlo?In python come potrei fare una copia profonda di un dict ad una profondità particolare?

Mi guardavo intorno per vedere se c'era una biblioteca che potevo usare o un esempio ma non riuscivo a trovare nulla. Sono abbastanza nuovo per Python, altrimenti scriverò la subroutine per farlo da solo. Qualche idea? I frammenti di codice sarebbero apprezzati in quanto sarebbe più veloce per me capire che una semplice spiegazione su come farlo.

Grazie.

INFORMAZIONI AGGIUNTIVE:

Alcuni hanno chiedere perché vorrei fare questo, ho bisogno di una copia (non un ref come sto andando a modificare alcuni dei valori e non voglio che l'originale modificato) di alcuni degli elementi da un dict ma il dict è enorme (molti dict di dicts) e quindi non voglio far saltare in aria la mia memoria impronta

mIO CODICE FINORA

Va bene, mi arrendo su. Questo è stato più difficile di quanto mi aspettassi e non ho il tempo di capirlo. Il mio ultimo tentativo con qualche codice di debug/test.

# 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 Non riesco a trovare un modo affidabile e coerente per determinare se l'elemento è iterabile. Ho letto il numero this post e ho cercato di capirlo, ma nessuna delle soluzioni sembrava funzionare per il mio caso di test.

Mi limiterò a copiare l'intero dict e cercherò di ottimizzare la soluzione in seguito (o meno).

Grazie ...

+3

Quale problema speri di risolvere facendo questo? –

+1

hai provato l'ovvio 'copy.deepcopy (x)' e 'pickle'? – zenpoy

+0

@zenpoy Ho guardato copy.deepcopy (x) ma non sembrava in grado di limitare la sua copia ad una particolare profondità. Non pensavo di usare pickle e non sono sicuro di come avrebbe funzionato, ma il tuo suggerimento mi ha fatto pensare che forse potresti ottenere il pprint per fare la copia in quanto ti permette di specificare una profondità ??? Devo pensare a come funzionerebbe comunque. – stephenmm

risposta

3

questo suona un po 'come 'plz darmi teh Codz' ...

In ogni caso, avrete bisogno di un metodo personalizzato a meno che non si vuole veramente incidere il funzionalità di iterables con sottoclassi. Pseudocodice:

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

In realtà, l'esempio precedente sarebbe solo copiare qualsiasi dizionario come è, perché se siamo a corto di profondità, dobbiamo solo copiare direttamente la restante parte. La versione corretta sarebbe:

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 

C'è una sottile differenza. (Sfortunatamente, non posso commentare la risposta)

+0

Questo salterà semplicemente aggiungendo l'elemento tutti insieme se è iterabile ma hai raggiunto la profondità massima. Copiare qualsiasi dizionario annidato oltre la profondità massima è esattamente ciò che non vogliamo fare. –

+0

ma saltare l'articolo se abbiamo raggiunto la profondità massima è quello che vogliamo fare, giusto? Il tuo codice è fondamentalmente equivalente a copy = original.copy(). –

+0

No, vogliamo copiare con ref, in sostanza, sotto la profondità massima durante la copia di val sopra. –

Problemi correlati