अजगर में एक ताना की गहरी प्रतिलिपि


341

मैं dictअजगर में एक की एक गहरी प्रतिलिपि बनाना चाहते हैं । दुर्भाग्य से .deepcopy()विधि के लिए मौजूद नहीं है dict। मैं उसको कैसे करू?

>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.deepcopy()
Traceback (most recent calll last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7

अंतिम पंक्ति होनी चाहिए 3

मैं चाहूंगा कि my_dictस्नैपशॉट पर प्रभाव न पड़े my_copy

मैं उसको कैसे करू? समाधान पायथन 3.x के साथ संगत होना चाहिए।


3
मुझे नहीं पता कि यह एक डुप्लिकेट है, लेकिन यह: stackoverflow.com/questions/838642/python-dEDIA-deepcopy भयानक रूप से करीब है।
charleslparker

जवाबों:


473

कैसा रहेगा:

import copy
d = { ... }
d2 = copy.deepcopy(d)

अजगर 2 या 3:

Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = copy.deepcopy(my_dict)
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
3
>>>

16
वास्तव में मेरे द्वारा दिए गए ओवरसाइम्प्लीफाइड उदाहरण के लिए यह काम करता है। मेरी चाबियाँ संख्याएं नहीं हैं, लेकिन वस्तुएं हैं। यदि मैं कॉपी मॉड्यूल प्रलेखन पढ़ता हूं, तो मुझे कुंजी के लिए __copy __ () / __ deepcopy __ () विधि घोषित करनी होगी। मुझे वहां तक ​​पहुंचाने के लिए बहुत-बहुत धन्यवाद!
ओलिवियर ग्रेजायर

3
क्या पायथन 3.2 और 2.7 कोड में कोई अंतर है? वे मुझे समान लगते हैं। यदि ऐसा है, तो कोड का एक एकल ब्लॉक और एक बयान "पायथन 3 और 2 दोनों के लिए काम करता है" बेहतर होगा
मेस्ट्रेलेयन

30
यह भी ध्यान देने योग्य copy.deepcopyहै कि धागा सुरक्षित नहीं है। इसका कठिन तरीका सीखा। दूसरी ओर, आपके उपयोग के मामले के आधार पर, json.loads(json.dumps(d)) है धागा सुरक्षित, और अच्छी तरह से काम करता है।
लूटने

1
@ आपको उत्तर के रूप में उस टिप्पणी को पोस्ट करना चाहिए। यह एक व्यवहार्य विकल्प है। धागा सुरक्षा अति सूक्ष्म अंतर एक महत्वपूर्ण अंतर है।
BuvinJ

3
@BuvinJ मुद्दा यह है कि json.loadsसभी उपयोग के मामलों के लिए समस्या का समाधान नहीं किया जाता है, जहां अजगर dictगुण JSON क्रमिक नहीं हैं। यह उन लोगों की मदद कर सकता है जो केवल उदाहरण के लिए एपीआई से सरल डेटा संरचनाओं के साथ काम कर रहे हैं, लेकिन मुझे नहीं लगता कि यह ओपी के सवाल का पूरी तरह से जवाब देने के लिए एक समाधान के लिए पर्याप्त है।
लूट

36

डिक्शनरी.कॉपी () डिक्शनरी
आईडी के लिए एक उथला कॉपी फ़ंक्शन है, जो फ़ंक्शन में अंतर्निहित है जो आपको चर का पता देता है

पहले आपको यह समझने की आवश्यकता है कि "यह विशेष समस्या क्यों हो रही है?"

In [1]: my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}

In [2]: my_copy = my_dict.copy()

In [3]: id(my_dict)
Out[3]: 140190444167808

In [4]: id(my_copy)
Out[4]: 140190444170328

In [5]: id(my_copy['a'])
Out[5]: 140190444024104

In [6]: id(my_dict['a'])
Out[6]: 140190444024104

कुंजी 'a' के लिए दोनों डिट्स में मौजूद सूची का पता उसी स्थान की ओर इशारा करता है।
इसलिए जब आप my_dict में सूची का मान बदलते हैं, तो my_copy में सूची भी बदल जाती है।


प्रश्न में उल्लिखित डेटा संरचना का समाधान:

In [7]: my_copy = {key: value[:] for key, value in my_dict.items()}

In [8]: id(my_copy['a'])
Out[8]: 140190444024176

या आप ऊपर बताए अनुसार डीपकोपी का उपयोग कर सकते हैं।


4
आपका समाधान नेस्टेड शब्दकोशों के लिए काम नहीं करता है। deepcopy उस कारण के लिए बेहतर है।
चार्ल्स प्लेजर

2
@CharlesPlager सहमत! लेकिन आपको यह भी ध्यान देना चाहिए कि सूची का टुकड़ा करना हुकुम पर काम नहीं करता है value[:]। समाधान एक सार्वभौमिक समाधान के बजाय प्रश्न में उल्लिखित विशेष डेटा संरचना के लिए था।
theBuzzyCoder

17

अजगर 3.x

कॉपी आयात से डीपकोपी

my_dict = {'one': 1, 'two': 2}
new_dict_deepcopy = deepcopy(my_dict)

डीपकोपी के बिना, मैं अपने डोमेन शब्दकोश के भीतर से होस्टनाम शब्दकोश को निकालने में असमर्थ हूं।

डीपकोपी के बिना मुझे निम्नलिखित त्रुटि मिलती है:

"RuntimeError: dictionary changed size during iteration"

... जब मैं अपने शब्दकोश से वांछित तत्व को दूसरे शब्दकोश के अंदर निकालने की कोशिश करता हूं।

import socket
import xml.etree.ElementTree as ET
from copy import deepcopy

डोमेन एक डिक्शनरी ऑब्जेक्ट है

def remove_hostname(domain, hostname):
    domain_copy = deepcopy(domain)
    for domains, hosts in domain_copy.items():
        for host, port in hosts.items():
           if host == hostname:
                del domain[domains][host]
    return domain

उदाहरण आउटपुट: [मूल] डोमेन = {'स्थानीयकरण': {'स्थानीयहोस्ट': {'सभी': '4000'}}}

[नया] डोमेन = {'स्थानीयकरण': {}}}

तो यहाँ क्या हो रहा है, मैं शब्दकोश की नकल पर ही शब्दकोश के ऊपर पुनरावृति करने के बजाय पुनरावृत्ति कर रहा हूँ। इस पद्धति से, आप आवश्यकतानुसार तत्वों को निकालने में सक्षम हैं।


-3

मुझे लसे वी। कार्लसन से बहुत कुछ पसंद है और सीखा है। मैंने इसे निम्नलिखित उदाहरण में संशोधित किया, जो उथली शब्दकोश प्रतियों और गहरी प्रतियों के बीच के अंतर को बहुत अच्छी तरह से उजागर करता है:

    import copy

    my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
    my_copy = copy.copy(my_dict)
    my_deepcopy = copy.deepcopy(my_dict)

अब अगर तुम बदलो

    my_dict['a'][2] = 7

और करो

    print("my_copy a[2]: ",my_copy['a'][2],",whereas my_deepcopy a[2]: ", my_deepcopy['a'][2])

आपको मिला

    >> my_copy a[2]:  7 ,whereas my_deepcopy a[2]:  3

1
आपको क्या लगता है कि यह उत्तर लेज़ वी। कार्लसन के उत्तर से अलग क्यों है ? यह क्या जोड़ता है कि अन्य उत्तर नहीं कहता है?
ओलिवियर ग्रेजायर

हाय, ओलिवियर! मैं लेसे वी। कार्लसन के उत्तर की योग्यता लेने की कोशिश नहीं कर रहा हूं - उन्होंने अनिवार्य रूप से मेरे पास मौजूद समस्या को हल किया, और मैं उनके कर्ज में डूबा हुआ हूं। मेरी टिप्पणी अलग नहीं है, यह सिर्फ पूरक है। साधारण कारण से कि यह "डीपकोपी" के साथ "कॉपी" के विपरीत है। यह मेरी समस्या का स्रोत था, जब मुझे उनके समकक्ष फैशन का उपयोग करते समय गलती हुई थी। चीयर्स।
राफेल मोंटेइरो

-9

एक सरल (मेरे विचार में) समाधान एक नया शब्दकोश बनाना है और इसे पुराने की सामग्री के साथ अद्यतन करना है:

my_dict={'a':1}

my_copy = {}

my_copy.update( my_dict )

my_dict['a']=2

my_dict['a']
Out[34]: 2

my_copy['a']
Out[35]: 1

इस दृष्टिकोण के साथ समस्या यह है कि यह पर्याप्त 'गहरा' नहीं हो सकता है। यानी पुनरावृत्ति गहरी नहीं है। साधारण वस्तुओं के लिए पर्याप्त है लेकिन नेस्टेड शब्दकोशों के लिए नहीं। यहाँ एक उदाहरण है जहाँ यह पर्याप्त गहरा नहीं हो सकता है:

my_dict1={'b':2}

my_dict2={'c':3}

my_dict3={ 'b': my_dict1, 'c':my_dict2 }

my_copy = {}

my_copy.update( my_dict3 )

my_dict1['b']='z'

my_copy
Out[42]: {'b': {'b': 'z'}, 'c': {'c': 3}}

डीपकोपी () का उपयोग करके मैं अर्ध-उथले व्यवहार को समाप्त कर सकता हूं, लेकिन मुझे लगता है कि किसी को यह तय करना होगा कि आपके आवेदन के लिए कौन सा दृष्टिकोण सही है। ज्यादातर मामलों में आप परवाह नहीं कर सकते हैं, लेकिन संभावित नुकसान के बारे में पता होना चाहिए ... अंतिम उदाहरण:

import copy

my_copy2 = copy.deepcopy( my_dict3 )

my_dict1['b']='99'

my_copy2
Out[46]: {'b': {'b': 'z'}, 'c': {'c': 3}}

12
यह हुकुम की उथली प्रतिलिपि बनाता है, जो वह नहीं है जो प्रश्नकर्ता पूछ रहा था। इसमें शामिल वस्तुओं को स्वयं कॉपी नहीं किया जाता है। और उथले नकल का एक आसान तरीका है my_dict.copy()!
ब्लेककनथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.