it-swarm.com.de

So kopieren Sie ein Wörterbuch und bearbeiten nur die Kopie

Kann mir das bitte jemand erklären? Das ergibt für mich keinen Sinn.

Ich kopiere ein Wörterbuch in ein anderes und bearbeite das zweite und beide werden geändert. Warum passiert dies?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
693
MadSc13ntist

Python nie kopiert implizit Objekte. Wenn Sie dict2 = dict1 festlegen, verweisen sie auf dasselbe Diktatobjekt. Wenn Sie es also mutieren, verweisen alle Verweise darauf weiterhin auf das Objekt in seinem aktuellen Zustand.

Wenn Sie das Diktat kopieren möchten (was selten vorkommt), müssen Sie dies explizit mit tun

dict2 = dict(dict1)

oder

dict2 = dict1.copy()
742
Mike Graham

Wenn Sie dict2 = dict1 zuweisen, erstellen Sie keine Kopie von dict1, was dazu führt, dass dict2 nur ein anderer Name für dict1 ist.

Um die veränderlichen Typen wie Wörterbücher zu kopieren, verwenden Sie copy/deepcopy des Moduls copy .

import copy

dict2 = copy.deepcopy(dict1)
517
Imran
>>> x={'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> u=x.copy()
>>> v=dict(x)
>>> import copy
>>> w=copy.deepcopy(x)
>>> x['a']=10
>>> x
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> u
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> v
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> w
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> x['b']['m']=40
>>> x
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> u
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> v
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> w
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
132
gpanda

Unter python 3.5+ ist es einfacher, eine flache Kopie mit dem Operator ** Unpackaging zu erstellen. Definiert durch Pep 448 .

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

** Entpackt das Wörterbuch in ein neues Wörterbuch, das dann dict2 zugewiesen wird.

Wir können auch bestätigen, dass jedes Wörterbuch eine eigene ID hat.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

Wenn eine tiefe Kopie benötigt wird, ist copy.deepcopy () immer noch der richtige Weg.

59
PabTorre

Die beste und einfachste Möglichkeit, eine Kopie zu erstellen eines Diktat in beiden Python 2.7 und ...

So erstellen Sie eine Kopie des einfachen (einstufigen) Wörterbuchs:

1. Verwenden Sie die Methode dict (), anstatt eine Referenz zu generieren, die auf das vorhandene Diktat verweist.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. Verwenden der integrierten pdate () Methode des python Wörterbuchs.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

So erstellen Sie eine Kopie des verschachtelten oder komplexen Wörterbuchs:

Verwenden Sie das integrierte Modul copy, das allgemeine flache und tiefe Kopiervorgänge bietet. Dieses Modul ist in Python 2.7 und 3 enthalten. *

import copy

my_dict2 = copy.deepcopy(my_dict1)
42
Emrit

Sie können auch einfach ein neues Wörterbuch mit einem Wörterbuchverständnis erstellen. Dadurch wird das Importieren von Kopien vermieden.

dout = dict((k,v) for k,v in mydict.items())

Natürlich können Sie in python> = 2.7 Folgendes tun:

dout = {k:v for k,v in mydict.items()}

Aus Gründen der Rückwärtskompatibilität ist die Top-Methode jedoch besser.

35

Zuweisungsanweisungen in Python kopieren keine Objekte, sondern erstellen Bindungen zwischen einem Ziel und einem Objekt.

also, dict2 = dict1, ergibt sich eine weitere Bindung zwischen dict2 und dem Objekt, auf das dict1 verweist.

wenn Sie ein Diktat kopieren möchten, können Sie den copy module verwenden. Das Kopiermodul hat zwei Schnittstellen:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

Der Unterschied zwischen flachem und tiefem Kopieren ist nur für zusammengesetzte Objekte relevant (Objekte, die andere Objekte enthalten, wie Listen oder Klasseninstanzen):

Eine flache Kopie erstellt ein neues zusammengesetztes Objekt und fügt dann (soweit möglich) Verweise auf die in gefundenen Objekte ein das Original.

Eine tiefe Kopie erstellt ein neues zusammengesetztes Objekt und fügt dann rekursiv Kopien der im Original gefundenen Objekte ein.

Zum Beispiel in python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

und das Ergebnis ist:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]
17
loosen

Zusätzlich zu den anderen bereitgestellten Lösungen können Sie _**_ verwenden, um das Wörterbuch in ein leeres Wörterbuch zu integrieren, z.

shallow_copy_of_other_dict = {**other_dict}.

Jetzt haben Sie eine "flache" Kopie von _other_dict_.

Angewandt auf Ihr Beispiel:

_>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>
_

Zeiger: Unterschied zwischen flachen und tiefen Kopien

16
d4rty

Sie können die neu erstellte Kopie auf einmal kopieren und bearbeiten, indem Sie den Konstruktor dict mit zusätzlichen Schlüsselwortargumenten aufrufen:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}
10
Frerich Raabe

Das hat mich anfangs auch verwirrt, weil ich einen C-Hintergrund hatte.

In C ist eine Variable ein Speicherort mit einem definierten Typ. Durch das Zuweisen zu einer Variablen werden die Daten in den Speicherort der Variablen kopiert.

In Python verhalten sich Variablen jedoch eher wie Zeiger auf Objekte. Wenn Sie also eine Variable einer anderen zuweisen, wird keine Kopie erstellt, sondern der Variablenname verweist auf dasselbe Objekt.

9
Craig McQueen

Jede Variable in python (Zeug wie dict1 oder str oder __builtins__ ist ein Zeiger auf ein verstecktes platonisches "Objekt" in der Maschine.

Wenn Sie dict1 = dict2 einstellen, zeigen Sie dict1 auf dasselbe Objekt (oder denselben Speicherort oder eine beliebige Analogie) wie dict2. Nun ist das Objekt, auf das dict1 verweist, dasselbe Objekt, auf das dict2 verweist.

Sie können überprüfen: dict1 is dict2 sollte True sein. Außerdem sollte id(dict1) mit id(dict2) identisch sein.

Sie möchten dict1 = copy(dict2) oder dict1 = deepcopy(dict2).

Der Unterschied zwischen copy und deepcopy? deepcopy stellt sicher, dass die Elemente von dict2 (haben Sie auf eine Liste gezeigt?) Auch Kopien sind.

Ich benutze deepcopy nicht viel - es ist normalerweise eine schlechte Übung, Code zu schreiben, der es benötigt (meiner Meinung nach).

7
wisty

dict2 = dict1 kopiert das Wörterbuch nicht. Sie geben dem Programmierer lediglich eine zweite Möglichkeit (dict2), auf dasselbe Wörterbuch zu verweisen.

6
user97370

dict1 ist ein Symbol, das auf ein zugrunde liegendes Wörterbuchobjekt verweist. Das Zuweisen von dict1 zu dict2 weist lediglich die gleiche Referenz zu. Wenn Sie den Wert eines Schlüssels über das Symbol dict2 ändern, wird das zugrunde liegende Objekt geändert, das sich auch auf dict1 auswirkt. Das ist verwirrend.

Es ist weitaus einfacher, unveränderliche Werte zu überdenken als Referenzen. Erstellen Sie daher Kopien, wann immer dies möglich ist:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

Dies ist syntaktisch dasselbe wie:

one_year_later = dict(person, age=26)
5
Petrus Theron
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

Es gibt viele Möglichkeiten, Dict-Objekte zu kopieren, die ich einfach benutze

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)
3
imcaozi

Wie andere bereits erklärt haben, macht der eingebaute dict nicht das, was Sie wollen. In Python2 (und wahrscheinlich auch in 3) können Sie problemlos eine ValueDict -Klasse erstellen, die mit = kopiert wird, sodass Sie sicher sein können, dass sich das Original nicht ändert.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

Bitte lesen Sie das hier beschriebene lvalue-Änderungsmuster: Python 2.7 - saubere Syntax für lvalue-Änderungen . Die wichtigste Beobachtung ist, dass str und int sich wie Werte in Python verhalten (obwohl sie tatsächlich unveränderliche Objekte unter der Haube sind). Beachten Sie dabei auch, dass str oder int nichts magisch Besonderes ist. dict kann auf die gleiche Weise verwendet werden, und ich kann mir viele Fälle vorstellen, in denen ValueDict Sinn ergibt.

1
personal_cloud

Schöne Erklärungen, ich möchte die einfachste Regel hinzufügen, auf die Sie sich beziehen können, wenn Sie an Python -Variablen denken, die Sie gleich = zuweisen. Wenn der Datentyp unveränderlich ist, müssen Sie sich keine Gedanken über das unerwartete Verhalten machen, auf das Sie gestoßen sind. Wenn der Datentyp änderbar ist, möchten Sie sicherstellen, dass Sie eine Kopie davon erstellen, um das unerwartete Verhalten zu verhindern, das Sie festgestellt haben.

nveränderliche Datentypen: Zeichenfolge (ein Tupel von Zeichen), Tupel

Veränderbare Datentypen: Liste, Array, Wörterbuch

1

Da python mit reference arbeitet, übergeben Sie bei dict2 = dict1 einen Verweis auf dict2, der mit dict1 identisch ist. Wenn Sie also dict1 oder dict2 ändern, ändern Sie eine Referenz, und beide diktieren Chages. Entschuldigung, wenn ich etwas in Englisch falsch gemacht habe.

1
Rodrigo Moraes

Nur für die Unterlagen. Ich verwende den folgenden Code, der auf Dikten basiert, die der JSON-Syntax mehr als dreimal schneller als DeepCopy folgen

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)
0

da dict2 = dict1 ist, enthält dict2 den Verweis auf dict1. Sowohl dict1 als auch dict2 zeigen auf dieselbe Stelle im Speicher. Dies ist nur ein normaler Fall bei der Arbeit mit veränderlichen Objekten in Python. Wenn Sie mit veränderlichen Objekten in python arbeiten, müssen Sie vorsichtig sein, da das Debuggen schwierig ist. Wie das folgende Beispiel.

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

In diesem Beispiel sollen alle Benutzer-IDs einschließlich blockierter IDs abgerufen werden. Das haben wir von der Variablen ids bekommen, aber wir haben auch den Wert von my_users ungewollt aktualisiert. Als Sie die IDs mit locked_ids erweitert haben, wurden meine_Benutzer aktualisiert, weil - ids beziehen sich auf my_users .

0