Een woordenboek kopiëren en alleen de kopie bewerken

Kan iemand mij dit uitleggen? Dit slaat voor mij nergens op.

Ik kopieer een woordenboek naar een ander en bewerk het tweede en beide worden gewijzigd. Waarom gebeurt dit?

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

Antwoord 1, autoriteit 100%

Python nooitkopieert impliciet objecten. Als je dict2 = dict1instelt, laat je ze verwijzen naar exact hetzelfde dict-object, dus als je het muteert, blijven alle verwijzingen ernaar verwijzen naar het object in zijn huidige staat.

Als je het dictaat wilt kopiëren (wat zeldzaam is), moet je dat expliciet doen met

dict2 = dict(dict1)

of

dict2 = dict1.copy()

Antwoord 2, autoriteit 78%

Wanneer u dict2 = dict1toewijst, maakt u geen kopie van dict1, maar resulteert in dict2als een andere naam voor dict1.

Om de veranderlijke typen zoals woordenboeken te kopiëren, gebruikt u copy/ deepcopyvan de copymodule.

import copy
dict2 = copy.deepcopy(dict1)

Antwoord 3, autoriteit 22%

Terwijl dict.copy()en dict(dict1)een kopie genereren, zijn het slechts ondiepekopieën. Als u een diepekopie wilt, is copy.deepcopy(dict1)vereist. Een voorbeeld:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

Wat betreft ondiepe versus diepe kopieën, uit de Python copy-module documenten:

Het verschil tussen oppervlakkig en diep kopiëren is alleen relevant voor samengestelde objecten (objecten die andere objecten bevatten, zoals lijsten of klasseninstanties):

  • Een oppervlakkige kopie construeert een nieuw samengesteld object en voegt er vervolgens (voor zover mogelijk) verwijzingen in naar de objecten in het origineel.
  • Een diepe kopie construeert een nieuw samengesteld object en voegt er vervolgens, recursief, kopieën in van de objecten die in het origineel zijn gevonden.

Antwoord 4, autoriteit 7%

Op python 3.5+ is er een eenvoudigere manier om een ​​ondiepe kopie te maken door de ** uitpakoperator te gebruiken. Gedefinieerd door 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?!'}

** pakt het woordenboek uit in een nieuw woordenboek dat vervolgens wordt toegewezen aan dict2.

We kunnen ook bevestigen dat elk woordenboek een aparte id heeft.

>>>id(dict1)
 178192816
>>>id(dict2)
 178192600

Als een diepe kopie nodig is, is copy.deepcopy()nog steeds de weg te gaan.


Antwoord 5, autoriteit 6%

In de diepte en een gemakkelijke manier om te onthouden:

Als je dict2 = dict1 doet, verwijst dict2 naar dict1. Zowel dict1 als dict2 wijzen naar dezelfde locatie in het geheugen. Dit is gewoon een normaal geval tijdens het werken met veranderlijke objecten in python. Wanneer u met veranderlijke objecten in python werkt, moet u voorzichtig zijn, aangezien het moeilijk te debuggen is.

In plaats van dict2 = dict1 te gebruiken, moet u de methode copy(ondiepe kopie) en deepcopygebruiken uit de module copyvan python om dict2 te scheiden van dict1.

De juiste manier is:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?"
>>> dict2
{'key1': 'value1', 'key2': 'WHY?'}
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>> id(dict1)
140641178056312
>>> id(dict2)
140641176198960
>>> 

Zoals je kunt zien is de idvan zowel dict1 als dict2 verschillend, wat betekent dat beide verwijzen naar/verwijzen naar verschillende locaties in het geheugen.

Deze oplossing werkt voor woordenboeken met onveranderlijke waarden, dit is niet de juiste oplossing voor woordenboeken met veranderlijke waarden.

Bijvoorbeeld:

>>> import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = dict1.copy()
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': False}}
>>> id(dict1)
140641197660704
>>> id(dict2)
140641196407832
>>> id(dict1["key2"])
140641176198960
>>> id(dict2["key2"])
140641176198960

Je kunt zien dat hoewel we copy voor dict1 hebben toegepast, de waarde van mutable is gewijzigd in false op zowel dict2 als dict1 hoewel we dit alleen op dict2 hebben gewijzigd. Dit komt omdat we de waarde van een veranderlijk dictaat van het dict1 hebben gewijzigd. Wanneer we een kopie op een dictaat toepassen, zal het alleen een oppervlakkige kopie maken, wat betekent dat het alle onveranderlijke waarden naar een nieuw dictaat kopieert en de veranderlijke waarden niet kopieert, maar ernaar verwijst.

De ultieme oplossing is om een ​​deepycopy van dict1 te maken om volledig een nieuw dict te maken met alle gekopieerde waarden, inclusief veranderlijke waarden.

>>>import copy
>>> dict1 = {"key1" : "value1", "key2": {"mutable": True}}
>>> dict2 = copy.deepcopy(dict1)
>>> dict2
{'key1': 'value1', 'key2': {'mutable': True}}
>>> id(dict1)
140641196228824
>>> id(dict2)
140641197662072
>>> id(dict1["key2"])
140641178056312
>>> id(dict2["key2"])
140641197662000
>>> dict2["key2"]["mutable"] = False
>>> dict2
{'key1': 'value1', 'key2': {'mutable': False}}
>>> dict1
{'key1': 'value1', 'key2': {'mutable': True}}

Zoals je kunt zien, zijn id’s anders, dit betekent dat dict2 een volledig nieuw dict is met alle waarden in dict1.

Deepcopy moet worden gebruikt als je een van de veranderlijke waarden wilt wijzigen zonder het oorspronkelijke dictaat te beïnvloeden. Als dat niet het geval is, kunt u een ondiepe kopie gebruiken. Deepcopy is traag omdat het recursief werkt om geneste waarden in het originele dictaat te kopiëren en ook extra geheugen in beslag neemt.


Antwoord 6, autoriteit 5%

De beste en gemakkelijkste manieren om een kopie te makenvan een dictin zowel Python 2.7 als 3zijn…

Een kopie maken van een eenvoudig (één-niveau) woordenboek:

1.De methode dict()gebruiken, in plaats van een verwijzing te genereren die naar het bestaande dictaat verwijst.

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.Met behulp van de ingebouwde update()-methode van het python-woordenboek.

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'}

Een kopie maken van een genest of complex woordenboek:

Gebruik de ingebouwde kopiemodule, die algemene, oppervlakkige en diepe kopieerbewerkingen biedt. Deze module is aanwezig in zowel Python 2.7 als 3.*

import copy
my_dict2 = copy.deepcopy(my_dict1)

Antwoord 7, autoriteit 4%

Je kunt ook gewoon een nieuw woordenboek maken met woordenboekbegrip. Dit voorkomt het importeren van kopieën.

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

Natuurlijk kun je in python >= 2.7 het volgende doen:

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

Maar voor achterwaartse compat. is de bovenste methode beter.


Antwoord 8, autoriteit 3%

Naast de andere aangeboden oplossingen, kunt u **gebruiken om het woordenboek te integreren in een leeg woordenboek, bijvoorbeeld

shallow_copy_of_other_dict = {**other_dict}.

Je hebt nu een “ondiepe” kopie van other_dict.

Toegepast op uw voorbeeld:

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

Aanwijzer: verschil tussen ondiepe en diepe kopieën


Antwoord 9, autoriteit 2%

Toewijzingsinstructies in Python kopiëren geen objecten, ze creëren bindingen tussen een doel en een object.

dus dict2 = dict1, het resulteert in een nieuwe binding tussen dict2en het object waarnaar dict1verwijst.

als je een dictaat wilt kopiëren, kun je de copy modulegebruiken.
De kopieermodule heeft twee interfaces:

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

Het verschil tussen oppervlakkig en diep kopiëren is alleen relevant voor samengestelde objecten (objecten die andere objecten bevatten, zoals lijsten of klasseninstanties):

Een ondiepe kopiemaakt een nieuw samengesteld object en voegt er vervolgens (voor zover mogelijk) verwijzingen in naar de objecten in het origineel.

Een diepe kopiemaakt een nieuw samengesteld object en voegt er vervolgens, recursief, kopieën in van de objecten die in het origineel zijn gevonden.

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

en het resultaat is:

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

Antwoord 10

Dit verwarde mij aanvankelijk ook, omdat ik uit een C-achtergrond kwam.

In C is een variabele een locatie in het geheugen met een gedefinieerd type. Toewijzen aan een variabele kopieert de gegevens naar de geheugenlocatie van de variabele.

Maar in Python gedragen variabelen zich meer als verwijzingen naar objecten. Dus het toewijzen van de ene variabele aan de andere maakt geen kopie, het zorgt er alleen voor dat die variabelenaam naar hetzelfde object verwijst.


Antwoord 11

U kunt de nieuw gemaakte kopie in één keer kopiëren en bewerken door de dict-constructor aan te roepen met aanvullende trefwoordargumenten:

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

Antwoord 12

Elke variabele in python (dingen zoals dict1of strof __builtins__is een verwijzing naar een verborgen platonisch “object” in de machine.

Als u dict1 = dict2instelt, wijst u dict1gewoon naar hetzelfde object (of geheugenlocatie, of welke analogie u maar wilt) als dict2. Nu is het object waarnaar wordt verwezen door dict1hetzelfde object waarnaar wordt verwezen door dict2.

Je kunt controleren: dict1 is dict2moet Truezijn. Ook moet id(dict1)hetzelfde zijn als id(dict2).

U wilt dict1 = copy(dict2), of dict1 = deepcopy(dict2).

Het verschil tussen copyen deepcopy? deepcopyzorgt ervoor dat de elementen van dict2(heb je het naar een lijst verwezen?) ook kopieën zijn.

Ik gebruik deepcopyniet veel – het is meestal een slechte gewoonte om code te schrijven die dit nodig heeft (naar mijn mening).


Antwoord 13

dict1is een symbool dat verwijst naar een onderliggend woordenboekobject. Het toewijzen van dict1aan dict2wijst slechts dezelfde referentie toe. Het wijzigen van de waarde van een sleutel via het symbool dict2verandert het onderliggende object, wat ook van invloed is op dict1. Dit is verwarrend.

Het is veel gemakkelijker om over onveranderlijke waarden te redeneren dan over referenties, dus maak waar mogelijk kopieën:

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

Dit is syntactisch hetzelfde als:

one_year_later = dict(person, age=26)

Antwoord 14

>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

Er zijn veel manieren om Dict-objecten te kopiëren, ik gebruik gewoon

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

Antwoord 15

dict2 = dict1kopieert het woordenboek niet. Het geeft je de programmeur gewoon een tweede manier (dict2) om naar hetzelfde woordenboek te verwijzen.


Antwoord 16

Zoals anderen hebben uitgelegd, doet het ingebouwde dictniet wat je wilt. Maar in Python2 (en waarschijnlijk ook 3) kun je eenvoudig een ValueDict-klasse maken die kopieert met =, zodat je zeker weet dat het origineel niet verandert.

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] = ..."

Raadpleeg het hier besproken lvalu-modificatiepatroon: Python 2.7 – schone syntaxis voor wijziging van de waarde. De belangrijkste observatie is dat stren intzich gedragen als waarden in Python (ook al zijn het eigenlijk onveranderlijke objecten onder de motorkap). Terwijl je dat observeert, moet je er ook rekening mee houden dat er niets magisch speciaals is aan strof int. dictkan op vrijwel dezelfde manieren worden gebruikt, en ik kan veel gevallen bedenken waarin ValueDictzinvol is.


Antwoord 17

de volgende code, die op dicts staat die de json-syntaxis meer dan 3 keer sneller volgt dan deepcopy

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)

Antwoord 18

Kopiëren met een for-lus:

orig = {"X2": 674.5, "X3": 245.0}
copy = {}
for key in orig:
    copy[key] = orig[key]
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

Antwoord 19

U kunt direct gebruiken:

dict2 = eval(repr(dict1))

waarbij object dict2 een onafhankelijke kopie is van dict1, zodat u dict2 kunt wijzigen zonder dict1 te beïnvloeden.

Dit werkt voor elk soort object.


Antwoord 20

Een andere schonere manier zou zijn om json te gebruiken. zie onderstaande code

>>> a = [{"name":"Onkar","Address": {"state":"MH","country":"India","innerAddress":{"city":"Pune"}}}]
>>> b = json.dumps(a)
>>> b = json.loads(b)
>>> id(a)
2334461105416
>>> id(b)
2334461105224
>>> a[0]["Address"]["innerAddress"]["city"]="Nagpur"
>>> a
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Nagpur'}}}]
>>> b
[{'name': 'Onkar', 'Address': {'state': 'MH', 'country': 'India', 'innerAddress': {'city': 'Pune'}}}]
>>> id(a[0]["Address"]["innerAddress"])
2334460618376
>>> id(b[0]["Address"]["innerAddress"])
2334424569880

Als u nog een woordenboek wilt maken, gebruikt u json.dumps() en vervolgens json.loads() op hetzelfde woordenboekobject. Je hebt een apart dict-object.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes