2012-03-20 8 views
5

Na przykład, jeśli mam dyktować dyktowanie lub dyktowanie tablic, ale chcę tylko "głęboko" skopiować do dwóch poziomów, czy istnieje prosty sposób na zrobienie tego?W python, w jaki sposób zrobić głęboką kopię dyktować do określonej głębokości?

Rozglądałem się, aby sprawdzić, czy istnieje biblioteka, której mogę użyć, lub przykład, ale nie mogłem nic znaleźć. Jestem całkiem nowy w Pythonie, bo inaczej sam napisałbym podprocedurę, aby to zrobić. Jakieś pomysły? Fragmenty kodu byłyby doceniane, ponieważ zrozumiałbym je szybciej niż wyjaśnienie, jak to zrobić.

Dzięki.

DODATKOWE INFO:

Niektóre mają zapytać dlaczego miałbym to zrobić, muszę kopię (nie Aref jak mam zamiar zmodyfikować niektóre z wartości, a nie chcę oryginału zmodyfikowana) niektórych elementów z dict ale dict jest ogromny (wiele DICT z dicts) i tak nie chcę dmuchać moje zużycie pamięci

mój kod SO FAR

Dobra, dam w górę. Było to trudniejsze, niż się spodziewałem i nie mam czasu, aby to rozgryźć. Moja ostatnia próba z pewnym kodem do debugowania/testowania.

# 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 

Nie mogę znaleźć wiarygodnego i spójnego sposobu określania, czy dany element jest możliwy do sprawdzenia. Czytałem przez this post i próbowałem to rozgryźć, ale żadne z rozwiązań nie sprawdziło się w moim przypadku testowym.

Po prostu głęboko skopiuję cały dyktat i spróbuję zoptymalizować rozwiązanie później (lub nie).

Dzięki ...

+3

Jakiego problemu masz zamiar rozwiązać, robiąc to? –

+1

czy wypróbowałeś oczywiste 'copy.deepcopy (x)' and 'pickle'? – zenpoy

+0

@zenpoy Spojrzałem na copy.deepcopy (x), ale nie udało mi się ograniczyć jego kopii do konkretnej głębokości. Nie myślałem, żeby użyć pikle i nie jestem pewien, jak to by działało, ale twoja sugestia sprawiła, że ​​pomyślałem, że może uda ci się uzyskać pprint, aby zrobić kopię, ponieważ pozwala ci to określić głębokość ??? Muszę się zastanowić, jak to będzie działać. – stephenmm

Odpowiedz

3

To brzmi trochę jak „plz daj mi teh codz” ...

W każdym razie, trzeba niestandardową metodę, chyba że naprawdę chce się włamać do góry funkcjonalność iterables z podklasami. Pseudokod:

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

Właściwie, poprzedni przykład po prostu skopiować dowolny słownika jak to jest, bo jeśli zabraknie głębokości, po prostu skopiować pozostałą część bezpośrednio. Prawidłowa wersja to:

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 

Istnieje subtelna różnica. (Niestety, nie mogę wypowiedzieć się na temat samej odpowiedzi)

+0

To pominie dodanie elementu razem, jeśli jest to możliwe, ale osiągnąłeś maksymalną głębokość. Kopiowanie dowolnego zagnieżdżonego słownika poza maksymalną głębią jest dokładnie tym, czego nie chcemy robić. –

+0

ale pomijanie elementu, jeśli osiągnęliśmy maksymalną głębokość, jest tym, co chcemy zrobić, prawda? Twój kod jest w zasadzie równoznaczny z copy = original.copy(). –

+0

Nie, chcemy skopiować przez ref, zasadniczo poniżej maks. Głębokości podczas kopiowania według val powyżej. –

Powiązane problemy