it-swarm.com.de

Wie kann ich eine Liste klonen oder kopieren?

Welche Möglichkeiten gibt es, eine Liste in Python zu klonen oder zu kopieren?

Während der Verwendung von new_list = my_list werden bei Änderungen an new_list jedes Mal my_list geändert. Warum ist das?

2189
aF.

Mit new_list = my_list haben Sie eigentlich keine zwei Listen. Die Zuweisung kopiert nur den Verweis auf die Liste, nicht die tatsächliche Liste, sodass sich sowohl new_list als auch my_list nach der Zuweisung auf dieselbe Liste beziehen.

Um die Liste tatsächlich zu kopieren, haben Sie verschiedene Möglichkeiten:

  • Sie können die eingebaute list.copy() -Methode verwenden (verfügbar seit Python 3.3):

    new_list = old_list.copy()
    
  • Sie können es schneiden:

    new_list = old_list[:]
    

    Alex Martelli's Meinung (zumindest zurück in 2007 ) dazu ist, dass es eine seltsame Syntax ist und es keinen Sinn macht, sie zu benutzen je. ;) (Der nächste ist seiner Meinung nach besser lesbar).

  • Sie können die eingebaute list() Funktion verwenden:

    new_list = list(old_list)
    
  • Sie können generisches copy.copy() verwenden:

    import copy
    new_list = copy.copy(old_list)
    

    Dies ist etwas langsamer als list(), da zuerst der Datentyp von old_list ermittelt werden muss.

  • Wenn die Liste Objekte enthält und Sie diese auch kopieren möchten, verwenden Sie generic copy.deepcopy() :

    import copy
    new_list = copy.deepcopy(old_list)
    

    Offensichtlich die langsamste und speicherintensivste Methode, aber manchmal unvermeidlich.

Beispiel:

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))

Ergebnis:

original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]
2919
Felix Kling

Felix hat bereits eine ausgezeichnete Antwort geliefert, aber ich dachte, ich würde einen Geschwindigkeitsvergleich der verschiedenen Methoden durchführen:

  1. 10,59 Sek. (105,9us/itn) - copy.deepcopy(old_list)
  2. 10,16 Sek. (101,6us/itn) - reine python Copy()-Methode, die Klassen mit deepcopy kopiert
  3. 1,488 Sek. (14,88us/itn) - reine python Copy()-Methode kopiert keine Klassen (nur Dikte/Listen/Tupel)
  4. 0,325 Sek. (3,25us/itn) - for item in old_list: new_list.append(item)
  5. 0,217 Sek. (2,17us/itn) - [i for i in old_list] (a Listenverständnis )
  6. 0,186 Sek. (1,86us/itn) - copy.copy(old_list)
  7. 0.075 sec (0.75us/itn) - list(old_list)
  8. 0.053 sec (0.53us/itn) - new_list = []; new_list.extend(old_list)
  9. 0.039 sec (0.39us/itn) - old_list[:] ( list slicing )

Das schnellste ist also List Slicing. Beachten Sie jedoch, dass copy.copy(), list[:] und list(list) im Gegensatz zu copy.deepcopy() und der python -Version keine Listen, Wörterbücher und Klasseninstanzen in die Liste kopieren. Wenn sich also die Originale ändern, ändern sich diese auch in der kopierten Liste und umgekehrt.

(Hier ist das Drehbuch, falls jemand Interesse hat oder Probleme aufwerfen möchte :)

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 __== '__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
545
cryo

Ich habe wurde gesagt dass Python 3.3+ fügt list.copy() hinz Methode, die so schnell wie das Schneiden sein sollte:

newlist = old_list.copy()

135

Welche Möglichkeiten gibt es, eine Liste in Python zu klonen oder zu kopieren?

In Python 3 kann eine flache Kopie erstellt werden mit:

a_copy = a_list.copy()

In Python 2 und 3 können Sie eine flache Kopie mit einem vollständigen Stück des Originals erhalten:

a_copy = a_list[:]

Erläuterung

Es gibt zwei semantische Möglichkeiten, eine Liste zu kopieren. Eine flache Kopie erstellt eine neue Liste derselben Objekte, eine tiefe Kopie erstellt eine neue Liste mit neuen äquivalenten Objekten.

Flache Liste kopieren

Eine flache Kopie kopiert nur die Liste selbst, bei der es sich um einen Container mit Verweisen auf die Objekte in der Liste handelt. Wenn die enthaltenen Objekte selbst veränderbar sind und eines geändert wird, wird die Änderung in beiden Listen widergespiegelt.

Es gibt verschiedene Möglichkeiten, dies in Python 2 und 3 zu tun. Die Python 2-Möglichkeiten funktionieren auch in Python 3.

Python 2

In Python 2 besteht die idiomatische Art, eine flache Kopie einer Liste zu erstellen, aus einem vollständigen Ausschnitt des Originals:

a_copy = a_list[:]

Sie können dasselbe auch erreichen, indem Sie die Liste über den Listenkonstruktor übergeben.

a_copy = list(a_list)

die Verwendung des Konstruktors ist jedoch weniger effizient:

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

Python 3

In Python 3 erhalten Listen die list.copy -Methode:

a_copy = a_list.copy()

In Python 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

Durch das Erstellen eines anderen Zeigers wird keine Kopie erstellt

Wenn Sie new_list = my_list verwenden, wird new_list bei jeder Änderung von my_list geändert. Warum ist das so?

my_list ist nur ein Name, der auf die aktuelle Liste im Speicher verweist. Wenn Sie sagen, dass new_list = my_list keine Kopie erstellt, fügen Sie nur einen anderen Namen hinzu, der auf die ursprüngliche Liste im Speicher verweist. Wir können ähnliche Probleme haben, wenn wir Listen kopieren.

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

Die Liste ist nur ein Array von Zeigern auf den Inhalt. Eine flache Kopie kopiert also nur die Zeiger. Sie haben also zwei verschiedene Listen, aber sie haben denselben Inhalt. Um Kopien des Inhalts zu erstellen, benötigen Sie eine tiefe Kopie.

Tiefe Kopien

Um eine tiefe Kopie einer Liste in Python 2 oder 3 zu erstellen, verwenden Sie deepcopy im copy -Modul :

import copy
a_deep_copy = copy.deepcopy(a_list)

Um zu demonstrieren, wie dies uns erlaubt, neue Unterlisten zu erstellen:

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

Wir sehen also, dass die tief kopierte Liste eine völlig andere Liste als das Original ist. Sie könnten Ihre eigene Funktion rollen - aber nicht. Mit der Deepcopy-Funktion der Standardbibliothek können Sie wahrscheinlich Fehler erzeugen, die Sie sonst nicht hätten.

Verwenden Sie nicht eval

Sie können dies als einen Weg zum Deepcopy betrachten, aber tun Sie es nicht:

problematic_deep_copy = eval(repr(a_list))
  1. Es ist gefährlich, besonders wenn Sie etwas aus einer Quelle bewerten, der Sie nicht vertrauen.
  2. Es ist nicht zuverlässig, wenn ein Subelement, das Sie kopieren, keine Repräsentation hat, die ausgewertet werden kann, um ein äquivalentes Element zu reproduzieren.
  3. Es ist auch weniger performant.

In 64-Bit-Python 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

auf 64-Bit-Python 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
120
Aaron Hall

Es gibt bereits viele Antworten, die Ihnen sagen, wie Sie eine ordnungsgemäße Kopie erstellen, aber keine sagt aus, warum Ihre ursprüngliche "Kopie" fehlgeschlagen ist.

Python speichert keine Werte in Variablen. es bindet Namen an Objekte. Ihre ursprüngliche Aufgabe hat das Objekt, auf das my_list verweist, auch an new_list gebunden. Unabhängig davon, welchen Namen Sie verwenden, gibt es immer noch nur eine Liste. Änderungen, die bei der Bezeichnung my_list vorgenommen wurden, werden bei der Bezeichnung new_list beibehalten. Jede andere Antwort auf diese Frage gibt Ihnen verschiedene Möglichkeiten, ein neues Objekt zu erstellen, das an new_list gebunden werden soll.

Jedes Element einer Liste verhält sich wie ein Name, indem jedes Element nicht ausschließlich an ein Objekt gebunden wird. Eine flache Kopie erstellt eine neue Liste, deren Elemente an dieselben Objekte wie zuvor gebunden sind.

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]

Um Ihre Listenkopie einen Schritt weiter zu führen, kopieren Sie jedes Objekt, auf das sich Ihre Liste bezieht, und binden Sie diese Elementkopien an eine neue Liste.

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

Dies ist noch keine tiefe Kopie, da jedes Element einer Liste auf andere Objekte verweisen kann, genau wie die Liste an ihre Elemente gebunden ist. So kopieren Sie rekursiv jedes Element in der Liste und anschließend jedes andere Objekt, auf das von jedem Element verwiesen wird, usw. Führen Sie eine Tiefenkopie durch.

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

Siehe die Dokumentation für weitere Informationen zu Eckfällen beim Kopieren.

51
jack

Benutze thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
34
Paul Tarjan

Pythons Idiom dafür ist newList = oldList[:]

32
erisco

Python 3.6-Timings

Hier sind die Timing-Ergebnisse mit Python 3.6.8. Denken Sie daran, dass diese Zeiten relativ zueinander und nicht absolut sind.

Ich habe mich nur an flache Kopien gehalten und einige neue Methoden hinzugefügt, die in Python2 nicht möglich waren, wie list.copy() (das Python3 Slice-Äquivalent ) und zwei Formen von Liste auspacken (*new_list, = list und new_list = [*list]):

METHOD                  TIME TAKEN
b = [*a]                2.75180600000021
b = a * 1               3.50215399999990
b = a[:]                3.78278899999986  # Python2 winner (see above)
b = a.copy()            4.20556500000020  # Python3 "slice equivalent" (see above)
b = []; b.extend(a)     4.68069800000012
b = a[0:len(a)]         6.84498999999959
*b, = a                 7.54031799999984
b = list(a)             7.75815899999997
b = [i for i in a]      18.4886440000000
b = copy.copy(a)        18.8254879999999
b = []
for item in a:
  b.append(item)        35.4729199999997

Wir können sehen, dass der Python2-Gewinner immer noch gut abschneidet, aber Python3 list.copy() nicht wesentlich verdrängt, insbesondere angesichts der hervorragenden Lesbarkeit des letzteren.

Das dunkle Pferd ist die Auspack- und Umpackmethode (b = [*a]), die ~ 25% schneller ist als das rohe Schneiden und mehr als doppelt so schnell wie die andere Auspackmethode (*b, = a).

b = a * 1 macht sich auch überraschend gut.

Beachten Sie, dass diese Methoden keine äquivalenten Ergebnisse für andere Eingaben als Listen ausgeben. Sie funktionieren alle für Aufteilbare Objekte, einige funktionieren für jedes iterierbare Objekt, aber nur copy.copy() funktioniert für allgemeinere Python Objekte.


Hier ist der Testcode für Interessenten ( Vorlage von hier ):

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", 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\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\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 = []; for 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))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))
22
River

Fangen wir von vorne an und erforschen es ein wenig:

Angenommen, Sie haben zwei Listen:

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

Und wir müssen beide Listen kopieren, jetzt beginnend mit der ersten Liste:

Versuchen wir es also zunächst mit der allgemeinen Kopiermethode:

copy=list_1

Wenn Sie denken, dass Sie die Liste_1 kopiert haben, können Sie sich irren.

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))

ausgabe:

4329485320
4329485320

Überrascht? Ok Lass es uns erkunden:

Da wir wissen, dass python nichts in einer Variablen speichert, verweisen Variablen nur auf das Objekt, und das Objekt speichert den Wert. Hier ist das Objekt list, aber wir haben zwei Referenzen auf dasselbe Objekt mit zwei verschiedenen Variablennamen erstellt. Beide Variablen zeigen also auf dasselbe Objekt:

also, wenn du copy=list_1 tust, was ist das eigentlich?

enter image description here

Hier in der Bilderliste_1 und in copy sind zwei Variablennamen, aber das Objekt ist für beide Variablen gleich, die list sind.

Wenn Sie also versuchen, die kopierte Liste zu ändern, wird auch die ursprüngliche Liste geändert, da nur eine Liste vorhanden ist. Sie ändern diese Liste unabhängig von der kopierten Liste oder der ursprünglichen Liste:

copy[0]="modify"

print(copy)
print(list_1)

ausgabe:

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

So wurde die ursprüngliche Liste geändert:

Was ist dann die Lösung?

Lösung:

Gehen wir nun zu einer zweiten Pythonic-Methode zum Kopieren von Listen über:

copy_1=list_1[:]

Mit dieser Methode können wir das Problem beheben, mit dem wir in der ersten Ausgabe konfrontiert waren:

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

4338792136
4338791432

Wie wir sehen können, haben beide Listen unterschiedliche IDs und es bedeutet, dass beide Variablen auf unterschiedliche Objekte zeigen.

enter image description here

Versuchen wir nun, die Liste zu ändern und sehen wir uns an, ob das vorherige Problem weiterhin besteht:

copy_1[0]="modify"

print(list_1)
print(copy_1)

Ausgabe:

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

Wie Sie sehen, ändert es nicht die ursprüngliche Liste, sondern nur die kopierte Liste. Wir sind also damit einverstanden.

Also jetzt denke ich, wir sind fertig? Warten Sie, wir müssen auch die zweite verschachtelte Liste kopieren. Versuchen wir es also mit Pythonic:

copy_2=list_2[:]

Also sollte list_2 auf ein anderes Objekt verweisen, das eine Kopie von list_2 ist.

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

wir bekommen die Ausgabe:

4330403592 4330403528

Jetzt können wir davon ausgehen, dass beide Listen auf unterschiedliche Objekte verweisen. Versuchen wir nun, sie zu ändern und sehen, dass sie das geben, was wir wollen:

Wenn wir also versuchen:

copy_2[0][1]="modify"

print(list_2,copy_2)

es gibt uns die Ausgabe:

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

Nun, das ist etwas verwirrend, wir haben den Pythonic-Weg gewählt und stehen immer noch vor dem gleichen Problem.

lass es uns verstehen:

Also, wenn wir das tun:

copy_2=list_2[:]

wir kopieren nur die äußere Liste, nicht die verschachtelte Liste. Die verschachtelte Liste ist also dasselbe Objekt für beide Listen.

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

ausgabe:

4329485832
4329485832

Wenn wir also copy_2=list_2[:] machen, passiert Folgendes:

enter image description here

Es wird die Kopie der Liste erstellt, aber nur die Kopie der äußeren Liste, nicht die Kopie der verschachtelten Liste. Die verschachtelte Liste ist für beide Variablen gleich. Wenn Sie also versuchen, die verschachtelte Liste zu ändern, wird auch die ursprüngliche Liste geändert, da das Objekt der verschachtelten Liste für beide gleich ist verschachtelte Liste.

Also, was ist die Lösung?

Lösung ist deep copy

from copy import deepcopy
deep=deepcopy(list_2)

Also lasst es uns jetzt überprüfen:

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

ausgabe:

4322146056 4322148040

beide IDs sind unterschiedlich. Überprüfen wir nun die ID der verschachtelten Liste:

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

ausgabe:

4322145992
4322145800

Wie Sie sehen, sind beide IDs unterschiedlich. Daher können wir davon ausgehen, dass beide verschachtelten Listen jetzt auf unterschiedliche Objekte verweisen.

Wenn Sie also deep=deepcopy(list_2) ausführen, was tatsächlich passiert:

enter image description here

Daher zeigen beide verschachtelten Listen auf unterschiedliche Objekte und verfügen jetzt über eine separate Kopie der verschachtelten Liste.

Versuchen wir nun, die verschachtelte Liste zu ändern und sehen wir, ob das vorherige Problem behoben wurde oder nicht:

also wenn wir das tun:

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

ausgabe:

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

Wie Sie sehen, hat es die ursprüngliche verschachtelte Liste nicht geändert, sondern nur die kopierte Liste.

Wenn dir meine ausführliche Antwort gefällt, lass es mich wissen, indem du sie hochnimmst. Wenn du Zweifel hast, diese Antwort beantwortet zu haben, schreibe einen Kommentar :)

19
Aaditya Ura

Alle anderen Mitwirkenden gaben großartige Antworten, die funktionieren, wenn Sie eine eindimensionale (abgestufte) Liste haben, jedoch nur copy.deepcopy() klont/kopiert eine Liste und zeigt nicht auf die verschachtelten list Objekte, wenn Sie mit mehrdimensionalen, verschachtelten Listen (Listenliste) arbeiten. Während Felix Kling in seiner Antwort darauf verweist, gibt es ein bisschen mehr zu dem Problem und möglicherweise eine Problemumgehung mit integrierten Funktionen, die sich als schnellere Alternative zu deepcopy erweisen könnten.

Während new_list = old_list[:], copy.copy(old_list)' und für Py3k old_list.copy() für einstufige Listen arbeiten, kehren sie zum Verweisen auf die list Objekte zurück, die im old_list und im new_list verschachtelt sind, und ändern sich zu einem der list Objekte werden im anderen verewigt.

Bearbeiten: Neue Informationen ans Licht gebracht

Wie sowohl Aaron Hall als auch PM 2Ring hervorgehoben haben, ist die Verwendung von eval() nicht nur eine schlechte Idee, sondern auch eine schlechte viel langsamer als copy.deepcopy().

Dies bedeutet, dass für mehrdimensionale Listen die einzige Option copy.deepcopy() ist. Dies ist jedoch keine Option, da die Leistung weit nach Süden geht, wenn Sie versuchen, sie in einem mehrdimensionalen Array mittlerer Größe zu verwenden. Ich habe versucht, timeit mit einem 42x42-Array zu verwenden, das für Bioinformatik-Anwendungen nicht unbekannt oder gar so groß ist, und habe aufgehört, auf eine Antwort zu warten.

Es scheint, dass die einzige echte Option darin besteht, mehrere Listen zu initialisieren und unabhängig voneinander zu bearbeiten. Wenn jemand andere Vorschläge zur Handhabung des mehrdimensionalen Listenkopierens hat, wäre er dankbar.

Wie bereits erwähnt, gibt es erhebliche Leistungsprobleme bei Verwendung des Moduls copy und von copy.deepcopy für mehrdimensionale Listen .

18
AMR

Es überrascht mich, dass dies noch nicht erwähnt wurde, der Vollständigkeit halber ...

Sie können das Entpacken von Listen mit dem "splat operator" durchführen: *, der auch Elemente Ihrer Liste kopiert.

old_list = [1, 2, 3]

new_list = [*old_list]

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

Der offensichtliche Nachteil dieser Methode ist, dass sie nur in Python 3.5+ verfügbar ist.

In Bezug auf das Timing scheint dies jedoch eine bessere Leistung zu erbringen als andere übliche Methoden.

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)
11
SCB

Beachten Sie, dass in einigen Fällen, in denen Sie eine eigene benutzerdefinierte Klasse definiert haben und die Attribute beibehalten möchten, anstelle der Alternativen copy.copy() oder copy.deepcopy() verwendet werden sollten, z. B. in Python 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))

Ausgänge:

lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
6
Chris_Rands

Ein sehr einfacher Ansatz, unabhängig von der python -Version, fehlte in bereits gegebenen Antworten, die Sie die meiste Zeit verwenden können (zumindest ich):

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

Wenn my_list jedoch andere Container enthält (z. B. verschachtelte Listen), müssen Sie deepcopy wie in den obigen Antworten aus der Kopierbibliothek vorgeschlagen verwenden. Zum Beispiel:

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

.Bonus: Wenn Sie keine Elemente kopieren möchten, verwenden Sie (auch als flache Kopie bezeichnet):

new_list = my_list[:]

Lassen Sie uns den Unterschied zwischen Lösung 1 und Lösung 2 verstehen

>>> 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])

Wie Sie sehen können, hat Lösung 1 perfekt funktioniert, als wir nicht die verschachtelten Listen verwendet haben. Lassen Sie uns überprüfen, was passieren wird, wenn wir Lösung 1 auf verschachtelte Listen anwenden.

>>> 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
5
jainashish
new_list = my_list[:]

new_list = my_list Versuchen Sie das zu verstehen. Angenommen, meine_Liste befindet sich im Heap-Speicher an Position X, d. H. Meine_Liste zeigt auf das X. Durch Zuweisen von new_list = my_list lassen Sie neue_Liste auf das X zeigen. Dies wird als flache Kopie bezeichnet.

Wenn Sie nun new_list = my_list[:] zuweisen, kopieren Sie einfach jedes Objekt von my_list in new_list. Dies wird als Deep Copy bezeichnet.

Die andere Möglichkeit, dies zu tun, ist:

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)
3
Ravi Shankar

in python, wenn Sie Wert für Variable definiert und diese Variable einer anderen zugewiesen haben,

die zweite Variable hat nur eine Referenz anstelle des kopierten Werts.

>>> l = [1,2,3]
>>> k = l
>>> l[0] = 10
>>> l
[10, 2, 3]
>>> k
[10, 2, 3]

wenn Sie also etwas in l & k ändern, wird dies beide betreffen

verwenden Sie zum Kopieren [::], so dass das Original keinen Einfluss darauf hat, ob Sie die Zuordnung abgeschlossen haben.

>>> k = l[::]
>>> k
[10, 2, 3]
>>> l[0] = 100
>>> l
[100, 2, 3]
>>> k
[10, 2, 3]