Jak sklonować lub skopiować listę?

Jakie są opcje klonowania lub kopiowania listy w Pythonie?

Użycie new_list = my_list następnie modyfikuje new_list za każdym razem, gdy my_list się zmienia.
Dlaczego?

Author: Taryn, 2010-04-10

18 answers

Z new_list = my_list, tak naprawdę nie masz dwóch list. Przypisanie po prostu kopiuje odniesienie do listy, a nie rzeczywistej listy, więc zarówno new_list, jak i my_list odnoszą się do tej samej listy po przypisaniu.

Aby skopiować listę, masz różne możliwości:

  • Możesz użyć wbudowanego list.copy() metoda (dostępna od Pythona 3.3):

    new_list = old_list.copy()
    
  • Możesz go pokroić:

    new_list = old_list[:]
    

    Opinia Alexa Martelli (przynajmniej w 2007 ) chodzi o to, że jest to dziwna składnia i nie ma sensu jej używać kiedykolwiek . ;) (Jego zdaniem następny jest bardziej czytelny).

  • Możesz użyć wbudowanego list() funkcja:

    new_list = list(old_list)
    
  • Możesz użyć generic copy.copy():

    import copy
    new_list = copy.copy(old_list)
    

    Jest to trochę wolniejsze niż list(), ponieważ najpierw musi poznać typ danych old_list.

  • Jeśli lista zawiera obiekty i chcesz je również skopiować, użyj generic copy.deepcopy():

    import copy
    new_list = copy.deepcopy(old_list)
    
    Oczywiście najwolniejsza i najbardziej wymagająca pamięci metoda, ale czasami nieunikniona.

Przykład:

import copy

class Foo(object):
    def __init__(self, val):
         self.val = val

    def __repr__(self):
        return str(self.val)

foo = Foo(1)

a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)

# edit orignal list and instance 
a.append('baz')
foo.val = 5

print('original: %r\n list.copy(): %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r'
      % (a, b, c, d, e, f))

Wynik:

original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]
 2438
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-23 15:38:38

Felix już dostarczył doskonałą odpowiedź, ale pomyślałem, że zrobię porównanie prędkości różnych metod:

  1. 10.59 sec (105.9 us / itn) - copy.deepcopy(old_list)
  2. 10.16 sec (101.6 us/itn) - czysty python Copy() metoda kopiowania klas za pomocą deepcopy
  3. [18]} 1.488 sec (14.88 us/itn) - czysta metoda Pythona Copy() nie kopiuje klas (tylko dicty/listy/krotki)
  4. 0.325 sec (3.25 us/itn) - for item in old_list: new_list.append(item)
  5. 0.217 sec (2.17 us/itn) - [i for i in old_list] (a lista zrozumienie )
  6. 0.186 sec (1.86 us / itn) - copy.copy(old_list)
  7. 0.075 sec (0.75 us/itn) - list(old_list)
  8. 0.053 sec (0.53 us/itn) - new_list = []; new_list.extend(old_list)
  9. 0.039 sek (0.39 us / itn) - old_list[:] (lista krojenia )

Więc najszybsze jest krojenie listy. Ale należy pamiętać, że copy.copy(), list[:] i list(list), W przeciwieństwie do copy.deepcopy() i wersji Pythona nie kopiują żadnych list, słowników I instancji klas na liście, więc jeśli oryginały się zmienią, zmienią się w skopiowanym lista też i vice versa.

(Oto scenariusz, jeśli ktoś jest zainteresowany lub chce poruszyć jakieś problemy:)

from copy import deepcopy

class old_class:
    def __init__(self):
        self.blah = 'blah'

class new_class(object):
    def __init__(self):
        self.blah = 'blah'

dignore = {str: None, unicode: None, int: None, type(None): None}

def Copy(obj, use_deepcopy=True):
    t = type(obj)

    if t in (list, tuple):
        if t == tuple:
            # Convert to a list if a tuple to 
            # allow assigning to when copying
            is_tuple = True
            obj = list(obj)
        else: 
            # Otherwise just do a quick slice copy
            obj = obj[:]
            is_tuple = False

        # Copy each item recursively
        for x in xrange(len(obj)):
            if type(obj[x]) in dignore:
                continue
            obj[x] = Copy(obj[x], use_deepcopy)

        if is_tuple: 
            # Convert back into a tuple again
            obj = tuple(obj)

    elif t == dict: 
        # Use the fast shallow dict copy() method and copy any 
        # values which aren't immutable (like lists, dicts etc)
        obj = obj.copy()
        for k in obj:
            if type(obj[k]) in dignore:
                continue
            obj[k] = Copy(obj[k], use_deepcopy)

    elif t in dignore: 
        # Numeric or string/unicode? 
        # It's immutable, so ignore it!
        pass 

    elif use_deepcopy: 
        obj = deepcopy(obj)
    return obj

if __name__ == '__main__':
    import copy
    from time import time

    num_times = 100000
    L = [None, 'blah', 1, 543.4532, 
         ['foo'], ('bar',), {'blah': 'blah'},
         old_class(), new_class()]

    t = time()
    for i in xrange(num_times):
        Copy(L)
    print 'Custom Copy:', time()-t

    t = time()
    for i in xrange(num_times):
        Copy(L, use_deepcopy=False)
    print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t

    t = time()
    for i in xrange(num_times):
        copy.copy(L)
    print 'copy.copy:', time()-t

    t = time()
    for i in xrange(num_times):
        copy.deepcopy(L)
    print 'copy.deepcopy:', time()-t

    t = time()
    for i in xrange(num_times):
        L[:]
    print 'list slicing [:]:', time()-t

    t = time()
    for i in xrange(num_times):
        list(L)
    print 'list(L):', time()-t

    t = time()
    for i in xrange(num_times):
        [i for i in L]
    print 'list expression(L):', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(L)
    print 'list extend:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        for y in L:
            a.append(y)
    print 'list append:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(i for i in L)
    print 'generator expression extend:', time()-t

EDIT : Dodano nowe, stare klasy i dicty do benchmarków, a wersja Pythona była znacznie szybsza i dodano kilka innych metod, w tym wyrażenia list i extend().

 461
Author: cryo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-28 23:29:35

Powiedziano miże Python 3.3 + dodaje list.copy() metoda, która powinna być tak szybka jak krojenie:

newlist = old_list.copy()

 118
Author: anatoly techtonik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-05 01:13:42

Jakie są opcje klonowania lub kopiowania listy w Pythonie?

W Pythonie 3 płytka Kopia może być wykonana za pomocą:

a_copy = a_list.copy()

W Pythonie 2 i 3 można uzyskać płytką kopię z pełnym fragmentem oryginału:

a_copy = a_list[:]

Wyjaśnienie

Istnieją dwa semantyczne sposoby kopiowania listy. Płytka Kopia tworzy nową listę tych samych obiektów, a głęboka Kopia tworzy nową listę zawierającą nowe równoważne obiekty.

Shallow list copy

A shallow copy kopiuje tylko samą listę, która jest kontenerem odniesień do obiektów na liście. Jeśli obiekty same w sobie są mutowalne i jeden z nich zostanie zmieniony, zmiana zostanie odzwierciedlona w obu listach.

Istnieją różne sposoby, aby to zrobić w Pythonie 2 i 3. Sposoby Pythona 2 będą również działać w Pythonie 3.

Python 2

W Pythonie 2 idiomatyczny sposób tworzenia płytkiej kopii listy jest z kompletnym fragmentem oryginału:
a_copy = a_list[:]

Ty może również wykonać to samo, przekazując listę przez konstruktor listy,

a_copy = list(a_list)

Ale użycie konstruktora jest mniej efektywne:

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

Python 3

W Pythonie 3 listy otrzymują metodę list.copy:

a_copy = a_list.copy()

W Pythonie 3.5:

>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125

Robienie kolejnego wskaźnika robi a nie robi kopię

Użycie new_list = my_list powoduje modyfikację new_list za każdym razem, gdy zmieni się my_list. Dlaczego?

my_list na tylko nazwa, która wskazuje na aktualną listę w pamięci. Kiedy mówisz new_list = my_list, że nie robisz kopii, po prostu dodajesz inną nazwę, która wskazuje na oryginalną listę w pamięci. Możemy mieć podobne problemy, gdy robimy kopie list.

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

Lista jest tylko tablicą wskaźników do zawartości, więc płytka Kopia po prostu kopiuje wskaźniki, a więc masz dwie różne listy, ale mają tę samą zawartość. Aby wykonać kopie zawartości, potrzebujesz głębokiej kopii.

Deep kopie

Aby utworzyć głęboką kopię listy, w Pythonie 2 lub 3, Użyj deepcopy w module copy :

import copy
a_deep_copy = copy.deepcopy(a_list)

Aby zademonstrować, w jaki sposób pozwala nam to tworzyć nowe podlisty:

>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]

Widzimy więc, że głęboko skopiowana lista jest zupełnie inną listą niż oryginalna. Możesz zwijać swoją własną funkcję-ale nie rób tego. prawdopodobnie stworzysz błędy, których w przeciwnym razie nie miałbyś, używając standardowej funkcji deepcopy w bibliotece.

Nie używaj eval

Możesz to zobaczyć jako sposób na deepcopy, ale nie rób tego:]}
problematic_deep_copy = eval(repr(a_list))
    To niebezpieczne, szczególnie jeśli oceniasz coś ze źródła, któremu nie ufasz.
  1. to nie jest wiarygodne, jeśli podelement, który kopiujesz, nie ma reprezentacji, która może być ewalowana w celu odtworzenia równoważnego elementu.
  2. Jest też mniej wydajny.

W 64-bitowym Pythonie 2.7:

>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206

NA 64-bitowym Pythonie 3.5:

>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644
 91
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 15:33:11

Istnieje już wiele odpowiedzi, które mówią, jak zrobić właściwą kopię, ale żadna z nich nie mówi, dlaczego oryginalna 'kopia' nie powiodła się.

Python nie przechowuje wartości w zmiennych; wiąże nazwy z obiektami. Twoje pierwotne zadanie zabrało obiekt, o którym mowa przez my_list i powiązało go z new_list. Bez względu na to, której nazwy użyjesz, nadal jest tylko jedna lista, więc zmiany wprowadzone podczas odwoływania się do niej jako my_list będą trwać przy odwoływaniu się do niej jako new_list. Każda z pozostałych odpowiedzi na to pytanie daje różne sposoby tworzenia nowego obiektu do powiązania new_list.

Każdy element listy działa jak nazwa, ponieważ każdy element wiąże się nie-wyłącznie z obiektem. Płytka Kopia tworzy nową listę, której elementy wiążą się z tymi samymi obiektami, co poprzednio.

new_list = list(my_list)  # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]

Aby posunąć Listę o krok dalej, skopiuj każdy obiekt, do którego odnosi się lista i powiązaj te kopie z nową listą.

import copy  
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]

Nie jest to jeszcze głęboka Kopia, ponieważ każdy element listy może odnosić się do innych obiektów, podobnie jak lista jest związana z jej elementami. Aby rekurencyjnie skopiować każdy element na liście, a następnie każdy inny obiekt, do którego odnosi się każdy element, i tak dalej: wykonaj głęboką kopię.

import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)

Patrz dokumentacja aby uzyskać więcej informacji na temat przypadków narożnych w kopiowaniu.

 42
Author: jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 16:00:21

new_list = list(old_list)

 31
Author: user285176,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-10 09:03:03

Użyj thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
 27
Author: Paul Tarjan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-10 08:53:06

Idiom Pythona do robienia tego to newList = oldList[:]

 26
Author: erisco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-10 08:53:19

Wszyscy inni współpracownicy DaliŚwietne odpowiedzi, które działają, gdy masz jedną listę wymiarową (wyrównaną), jednak z metod wymienionych do tej pory, tylko copy.deepcopy() działa, aby klonować/kopiować listę i nie wskazywać na zagnieżdżone obiekty list podczas pracy z wielowymiarowymi, zagnieżdżonymi listami (list of lists). Podczas gdy Felix Kling odnosi się do tego w swojej odpowiedzi, jest trochę więcej do problemu i ewentualnie obejście za pomocą wbudowanych, które mogą okazać się szybsze alternatywa dla deepcopy.

While new_list = old_list[:], copy.copy(old_list)' i dla Py3k old_list.copy() działa dla list jednopoziomowych, wracają do wskazywania na obiekty list zagnieżdżone w old_list i new_list, a zmiany w jednym z obiektów list są utrwalane w drugim.

Edit: New information bringed to light

Jak zauważył zarówno Aaron Hall jak i PM 2RING używanie eval() jest nie tylko złym pomysłem, jest również znacznie wolniejsze niż copy.deepcopy().

Oznacza to, że dla list wielowymiarowych jedyną opcją jest copy.deepcopy(). Mając to na uwadze, naprawdę nie jest to opcja, ponieważ wydajność idzie na południe, gdy próbujesz jej użyć na średniej wielkości tablicy wielowymiarowej. Próbowałem timeit użyć tablicy 42x42, nie niespotykanej ani nawet tak dużej do zastosowań bioinformatycznych, i zrezygnowałem z czekania na odpowiedź i zacząłem pisać moją edycję do tego posta.

Wydaje się, że jedyną realną opcją jest aby zainicjować wiele list i pracować nad nimi niezależnie. Jeśli ktoś ma jakieś inne sugestie, jak radzić sobie z wielowymiarowym kopiowaniem list, byłoby to mile widziane.

Jak stwierdzili inni, tam może być są istotne problemy z wydajnością przy użyciu modułu copy oraz copy.deepcopy Dla list wielowymiarowych. próbuje wypracować inny sposób kopiowania wielowymiarowej listy bez użycia deepcopy, (byłem pracując nad problemem dla kursu, który pozwala tylko 5 sekund na uruchomienie całego algorytmu w celu otrzymania kredytu), wymyśliłem sposób użycia wbudowanych funkcji do zrobienia kopii zagnieżdżonej listy bez konieczności ich wskazywania na siebie lub na zagnieżdżone w nich obiekty list. Użyłem eval() i repr() w przypisaniu, aby skopiować starą listę do nowej listy bez tworzenia linku do starej listy. Przyjmuje formę:

new_list = eval(repr(old_list))

Zasadniczo co to robi tworzy reprezentację old_list jako łańcuch znaków, a następnie ocenia łańcuch tak, jakby był obiektem reprezentowanym przez łańcuch znaków. W ten sposób nie tworzy się żadnego linku do oryginalnego obiektu list. Tworzony jest nowy obiekt list, a każda zmienna wskazuje na własny niezależny obiekt. Oto przykład użycia 2-wymiarowej zagnieżdżonej listy.

old_list = [[0 for j in range(y)] for i in range(x)] # initialize (x,y) nested list

# assign a copy of old_list to new list without them pointing to the same list object
new_list = eval(repr(old_list)) 

# make a change to new_list 
for j in range(y):
    for i in range(x):
    new_list[i][j] += 1

Jeśli następnie sprawdzisz zawartość każdej listy, na przykład listy 4 na 3, Python zwróci

>>> new_list

[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]

>>> old_list

[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

Podczas gdy to prawdopodobnie nie jest kanoniczny lub składniowo poprawny sposób, to wydaje się działać dobrze. Nie testowałem wydajności, ale zgaduję, że eval() i rep() będą miały mniej kosztów do uruchomienia niż deepcopy.

 18
Author: AMR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32

W przeciwieństwie do innych języków, które mają zmienną i wartość, Python ma nazwę i obiekt .

To stwierdzenie:

a = [1,2,3]

Oznacza nadanie liście (obiektowi) nazwy a, a to:

b = a

Po prostu daje temu samemu obiektowi a nową nazwę b, więc za każdym razem, gdy robisz coś z a, obiekt zmienia się, a zatem b zmienia się.

Jedynym sposobem na zrobienie naprawdę kopii a jest utworzenie nowego obiektu tak jak inne odpowiedzi już powiedział.

Więcej o tym można zobaczyć tutaj .

 13
Author: Statham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-10 07:06:57

Python 3.6.0 Timings

Oto wyniki pomiaru czasu za pomocą Pythona 3.6.0. Należy pamiętać, że te czasy są względem siebie, a nie absolutne.

Trzymałem się tylko płytkich kopii, a także dodałem kilka nowych metod, które nie były możliwe w Python2, takich jak list.copy() (odpowiednik python3 slice) i rozpakowywanie listy (*new_list, = list):

METHOD                  TIME TAKEN
b = a[:]                6.468942025996512   #Python2 winner
b = a.copy()            6.986593422974693   #Python3 "slice equivalent"
b = []; b.extend(a)     7.309216841997113
b = a[0:len(a)]         10.916740721993847
*b, = a                 11.046738261007704
b = list(a)             11.761539687984623
b = [i for i in a]      24.66165203397395
b = copy.copy(a)        30.853400873980718
b = []
for item in a:
  b.append(item)        48.19176080400939

Widzimy, że stary zwycięzca nadal wychodzi na szczyt, ale nie tak naprawdę o ogromną kwotę, biorąc pod uwagę zwiększoną czytelność podejścia Python3 list.copy().

Zauważ, że te metody Nie generują równoważne wyniki dla dowolnych danych wejściowych innych niż listy. wszystkie działają na obiektach, kilka działa na dowolnych iterowalnych, ale tylko copy.copy() działa na dowolnym obiekcie Pythona.


Oto kod testowy dla zainteresowanych stron (szablon stąd):

import timeit

COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'

print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []\nfor item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a:  b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
 12
Author: River,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-05 01:07:39

Zacznijmy od początku i zbadajmy to trochę głęboko:

Więc załóżmy, że masz dwie listy:

list_1=['01','98']
list_2=[['01','98']]

I musimy skopiować obie listy , teraz zaczynając od pierwszej listy:

Więc najpierw spróbujmy według ogólnej metody kopiowania:

copy=list_1

Teraz jeśli myślisz, że Kopiuj skopiuj listę_1 to możesz się mylić, sprawdźmy to:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

Wyjście:

4329485320
4329485320
Zaskoczony ? Ok, zbadajmy it:

Ponieważ wiemy, że python nie przechowuje niczego w zmiennej, zmienne odnoszą się tylko do obiektu, a obiekt przechowuje wartość. Tutaj obiekt jest list, ale stworzyliśmy dwa odwołania do tego samego obiektu przez dwie różne nazwy zmiennych. Tak więc obie zmienne wskazują na ten sam obiekt:

Więc kiedy robisz copy=list_1 co właściwie robi:

Tutaj wpisz opis obrazka

Tutaj na liście obrazka_1 i copy są dwie nazwy zmiennych, ale obiekt jest taki sam dla obie zmienne, które są list

Więc jeśli spróbujesz zmodyfikować skopiowaną listę, to zmieni ona również oryginalną listę, ponieważ lista jest tylko jedna, zmodyfikujesz tę listę bez względu na to, czy zrobisz to z skopiowanej listy, czy z oryginalnej listy:

copy[0]="modify"

print(copy)
print(list_1)

Wyjście:

['modify', '98']
['modify', '98']

Więc zmodyfikował oryginalną listę:

Jakie jest zatem rozwiązanie?

Rozwiązanie:

Przejdźmy teraz do drugiej pythonicznej metody kopiowania lista:

copy_1=list_1[:]

Teraz ta metoda napraw to, co mieliśmy do czynienia w pierwszym numerze sprawdźmy to:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

Więc jak możemy zobaczyć nasze obie listy mają różne id i oznacza to, że obie zmienne wskazują na różne obiekty, więc to, co się tutaj dzieje, to: {]}

Tutaj wpisz opis obrazka

Teraz spróbujmy zmodyfikować listę i zobaczmy, czy nadal mamy do czynienia z poprzednim problemem:

copy_1[0]="modify"

print(list_1)
print(copy_1)

Wyjście:

['01', '98']
['modify', '98']

Więc jak widać nie modyfikuje oryginalna lista, tylko zmodyfikowała skopiowaną listę, więc jesteśmy z nią w porządku.

Więc myślę, że skończyliśmy? poczekaj musimy skopiować drugą zagnieżdżoną listę, więc spróbujmy w pythonic sposób:
copy_2=list_2[:]

Zatem lista_2 powinna odnosić się do innego obiektu, który jest kopią lista_2 sprawdźmy:

print(id((list_2)),id(copy_2))

Otrzymujemy wyjście:

4330403592 4330403528

Teraz możemy założyć, że obie listy wskazują inny obiekt, więc spróbujmy go zmodyfikować i zobaczmy, czy daje to, co chcemy :

Więc kiedy spróbujemy:

copy_2[0][1]="modify"

print(list_2,copy_2)

Daje nam wyjście:

[['01', 'modify']] [['01', 'modify']]

Teraz, to jest trochę mylące użyliśmy sposobu pythonic i nadal, mamy do czynienia z tym samym problemem.

Zrozummy to:

Więc kiedy zrobimy:

copy_2=list_2[:]

W rzeczywistości kopiujemy tylko zewnętrzną listę, a nie zagnieżdżoną listę, więc zagnieżdżona lista jest tym samym obiektem dla obu list, sprawdźmy:

print(id(copy_2[0]))
print(id(list_2[0]))

Wyjście:

4329485832
4329485832

Więc właściwie, kiedy robimy copy_2=list_2[:] to jest to, co dzieje się:

Tutaj wpisz opis obrazka

Tworzy kopię listy, ale tylko zewnętrzną kopię listy, a nie zagnieżdżoną kopię listy, zagnieżdżona lista jest taka sama dla obu zmiennych, więc jeśli spróbujesz zmodyfikować zagnieżdżoną listę, to zmieni również oryginalną listę, ponieważ zagnieżdżony obiekt list jest taki sam dla obu zagnieżdżonych list.

Więc jakie jest rozwiązanie?

Rozwiązaniem jest deep copy

from copy import deepcopy
deep=deepcopy(list_2)

Więc teraz sprawdźmy to:

print(id((list_2)),id(deep))

Wyjście:

4322146056 4322148040

Oba id są Inne, teraz sprawdźmy ID zagnieżdżonej listy:

print(id(deep[0]))
print(id(list_2[0]))

Wyjście:

4322145992
4322145800

Jak widać oba id są różne, więc możemy założyć, że obie zagnieżdżone listy wskazują teraz inny obiekt.

Więc kiedy robisz deep=deepcopy(list_2) co się naprawdę dzieje :

Tutaj wpisz opis obrazka

Więc obie zagnieżdżone listy wskazują inny obiekt i mają teraz oddzielną kopię zagnieżdżonej listy.

Teraz spróbujmy zmodyfikować zagnieżdżoną listę i zobaczmy, czy rozwiązała poprzedni numer czy nie:

Więc jeśli zrobimy:

deep[0][1]="modify"
print(list_2,deep)

Wyjście:

[['01', '98']] [['01', 'modify']]

Więc jak widać nie zmodyfikował oryginalnej zagnieżdżonej listy, tylko zmodyfikował skopiowaną listę.

Jeśli podoba Ci się moja szczegółowa odpowiedź, daj mi znać, głosując na nią , jeśli masz jakiekolwiek wątpliwości co do tej odpowiedzi, komentuj:)

 12
Author: Ayodhyankit Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-13 07:04:17

Dziwi mnie, że jeszcze o tym nie wspomniano, więc dla kompletności...

Możesz rozpakować listę za pomocą "operatora splat": *, który również skopiuje elementy Twojej listy.

old_list = [1, 2, 3]

new_list = [*old_list]

new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]

Oczywistym minusem tej metody jest to, że jest ona dostępna tylko w Pythonie 3.5+.

Biorąc pod uwagę czas, wydaje się to działać lepiej niż inne popularne metody.

x = [random.random() for _ in range(1000)]

%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]

%timeit a = [*x]

#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
 7
Author: SCB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-26 02:33:47

Nie jestem pewien, czy jest to nadal aktualne, ale to samo zachowanie dotyczy również słowników. Spójrz na ten przykład.

a = {'par' : [1,21,3], 'sar' : [5,6,8]}
b = a
c = a.copy()
a['har'] = [1,2,3]

a
Out[14]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

b
Out[15]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

c
Out[16]: {'par': [1, 21, 3], 'sar': [5, 6, 8]}
 4
Author: Bobesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-08 08:39:37

Zauważ, że są przypadki, w których jeśli zdefiniowałeś własną klasę niestandardową i chcesz zachować atrybuty, powinieneś użyć copy.copy() lub copy.deepcopy() zamiast alternatyw, na przykład w Pythonie 3:

import copy

class MyList(list):
    pass

lst = MyList([1,2,3])

lst.name = 'custom list'

d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}


for k,v in d.items():
    print('lst: {}'.format(k), end=', ')
    try:
        name = v.name
    except AttributeError:
        name = 'NA'
    print('name: {}'.format(name))

Wyjścia:

lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
 3
Author: Chris_Rands,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 14:31:22
new_list = my_list[:]

new_list = my_list Spróbuj to zrozumieć. Załóżmy, że my_list znajduje się w pamięci sterty w lokalizacji X, tzn. my_list wskazuje na X. Teraz przypisując new_list = my_list pozwalasz new_list wskazywać na X. Jest to znane jako płytka Kopia.

Teraz, jeśli przypisujesz new_list = my_list[:], po prostu kopiujesz każdy obiekt my_list do new_list. Jest to znane jako głęboka Kopia.

W inny sposób można to zrobić są :

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)
 2
Author: Ravi Shankar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-26 21:03:30

W udzielonych już odpowiedziach brakowało bardzo prostego podejścia, niezależnego od wersji Pythona, z którego można korzystać przez większość czasu (przynajmniej ja):

new_list = my_list * 1       #Solution 1 when you are not using nested lists

Jeśli jednak my_list zawiera inne kontenery (np. listy zagnieżdżone) musisz użyć deepcopy tak, jak inni sugerowali w odpowiedziach powyżej z biblioteki kopiowania. Na przykład:

import copy
new_list = copy.deepcopy(my_list)   #Solution 2 when you are using nested lists

.Bonus : Jeśli nie chcesz kopiować elementów użyj (aka shallow copy):

new_list = my_list[:]

Let ' s understand difference between Rozwiązanie # 1 i Rozwiązanie #2

>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55 
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])

Jak widać rozwiązanie # 1 działało idealnie, gdy nie korzystaliśmy z zagnieżdżonych list. Sprawdźmy, co się stanie, gdy zastosujemy rozwiązanie #1 do zagnieżdżonych list.

>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]   #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]       #Solution #2 - DeepCopy worked in nested list
 2
Author: jainashish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-01 08:08:25

Możesz użyć funkcji bulit in list ():

newlist=list(oldlist)
Myślę, że ten kod ci pomoże.
 2
Author: Akash Nayak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-15 13:17:33