तानाशाही को समझना। () - उथला या गहरा?


429

के लिए प्रलेखन को पढ़ते हुए dict.copy(), यह कहता है कि यह शब्दकोश की उथली प्रतिलिपि बनाता है। मैं उसी पुस्तक का अनुसरण कर रहा हूं जिसका मैं अनुसरण कर रहा हूं (बेज़ले का पायथन संदर्भ), जो कहता है:

M.copy () विधि एक मैपिंग ऑब्जेक्ट में शामिल वस्तुओं की एक उथली प्रतिलिपि बनाता है और उन्हें एक नए मैपिंग ऑब्जेक्ट में रखता है।

इस पर विचार करो:

>>> original = dict(a=1, b=2)
>>> new = original.copy()
>>> new.update({'c': 3})
>>> original
{'a': 1, 'b': 2}
>>> new
{'a': 1, 'c': 3, 'b': 2}

इसलिए मैंने मान लिया कि यह original(और 'c': 3) के मूल्य को अद्यतन करेगा क्योंकि मैं भी एक उथली प्रति कर रहा था। जैसे यदि आप इसे सूची के लिए करते हैं:

>>> original = [1, 2, 3]
>>> new = original
>>> new.append(4)
>>> new, original
([1, 2, 3, 4], [1, 2, 3, 4])

यह उम्मीद के मुताबिक काम करता है।

चूंकि दोनों उथली प्रतियां हैं, इसलिए dict.copy()यह काम नहीं करता है जैसा कि मैं इसकी अपेक्षा करता हूं? या उथली बनाम गहरी नकल की मेरी समझ त्रुटिपूर्ण है?


2
काफी है कि वे "उथले" की व्याख्या नहीं करते हैं। अंदरूनी ज्ञान, पलक। बस तानाशाही और चाबी एक प्रति है, जबकि पहले स्तर के संदर्भों में नेस्टेड डाइक हैं, उदाहरण के लिए एक लूप में नहीं हटाया जा सकता है। इस प्रकार उस मामले में पायथन की तानाशाही () न तो उपयोगी है और न ही सहज। आपके प्रश्न के लिए धन्यवाद।
गीताप्रेस

जवाबों:


990

"उथले नकल" से इसका मतलब है कि शब्दकोश की सामग्री को मूल्य द्वारा कॉपी नहीं किया गया है, लेकिन सिर्फ एक नया संदर्भ बना रहा है।

>>> a = {1: [1,2,3]}
>>> b = a.copy()
>>> a, b
({1: [1, 2, 3]}, {1: [1, 2, 3]})
>>> a[1].append(4)
>>> a, b
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})

इसके विपरीत, एक गहरी प्रतिलिपि सभी सामग्रियों को मूल्य से कॉपी करेगी।

>>> import copy
>>> c = copy.deepcopy(a)
>>> a, c
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
>>> a[1].append(5)
>>> a, c
({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})

इसलिए:

  1. b = a: संदर्भ असाइनमेंट, बनाओ aऔर bएक ही वस्तु को इंगित करता है।

    'A = b': 'a' और 'b' दोनों का चित्रण '{1: L}', 'L' से '[1, 2, 3] की ओर इशारा करता है।

  2. b = a.copy(): उथला नकल, aऔर bदो अलग-थलग वस्तुओं बन जाएगा, लेकिन उनकी सामग्री अभी भी एक ही संदर्भ साझा करते हैं

    'B = a.copy ()': 'a' अंक '{1: L}', 'b' अंक '{1: M}', 'L' और 'M' दोनों बिंदुओं को '[] को इंगित करता है। १, २, ३] ’।

  3. b = copy.deepcopy(a): गहरी नकल, aऔर bसंरचना और सामग्री पूरी तरह से अलग हो जाते हैं।

    'B = copy.deepcopy (a)' का चित्रण: 'a' अंक '{1: L}', 'L' से '[1, 2, 3]' की ओर इशारा करता है;  'b' '{1: M}' की ओर इशारा करता है, 'M' '[1, 2, 3]' के एक अलग उदाहरण की ओर इशारा करता है।


अच्छा जवाब है, लेकिन आप अपने पहले वाक्य में व्याकरणिक त्रुटि को ठीक करने पर विचार कर सकते हैं। और Lफिर से उपयोग न करने का कोई कारण नहीं है b। ऐसा करने से उदाहरण सरल होगा।
टॉम रसेल

@kennytm: वास्तव में पहले दो उदाहरणों के बीच अंतर क्या है? आप वहाँ एक ही परिणाम मिलता है, लेकिन थोड़ा अलग आंतरिक कार्यान्वयन, लेकिन इससे क्या फर्क पड़ता है?
JavaSa

@TomRussell: या कोई भी, चूँकि यह सवाल काफी पुराना है, मेरा स्पष्टीकरण का सवाल हर किसी के लिए है
JavaSa

@JavaSa यह मायने रखता है कि, क्या आप कहते हैं b[1][0] = 5। यदि bएक उथली प्रतिलिपि है, तो आपने अभी-अभी बदला है a[1][0]
टॉम रसेल

2
महान स्पष्टीकरण, ... वास्तव में मेरा दिन बचा लिया! धन्यवाद ... क्या इस सूची को लागू किया जा सकता है, स्ट्रिंग, और अजगर के अन्य डेटाटिप्स?
भूरू

38

यह गहरी प्रतिलिपि या उथले प्रतिलिपि की बात नहीं है, आप जो भी कर रहे हैं, उनमें से कोई भी गहरी प्रतिलिपि नहीं है।

यहाँ:

>>> new = original 

आप सूची / मूल द्वारा संदर्भित सन्दर्भ के लिए एक नया संदर्भ बना रहे हैं।

यहाँ रहते हुए:

>>> new = original.copy()
>>> # or
>>> new = list(original) # dict(original)

आप एक नई सूची / तानाशाही बना रहे हैं जो मूल कंटेनर में निहित वस्तुओं के संदर्भों की एक प्रति से भरी हुई है।


31

इस उदाहरण को लें:

original = dict(a=1, b=2, c=dict(d=4, e=5))
new = original.copy()

अब 'उथले' (पहले) स्तर में एक मान बदलें:

new['a'] = 10
# new = {'a': 10, 'b': 2, 'c': {'d': 4, 'e': 5}}
# original = {'a': 1, 'b': 2, 'c': {'d': 4, 'e': 5}}
# no change in original, since ['a'] is an immutable integer

अब एक मान को एक स्तर और गहरा करते हैं:

new['c']['d'] = 40
# new = {'a': 10, 'b': 2, 'c': {'d': 40, 'e': 5}}
# original = {'a': 1, 'b': 2, 'c': {'d': 40, 'e': 5}}
# new['c'] points to the same original['d'] mutable dictionary, so it will be changed

8
no change in original, since ['a'] is an immutable integerइस। यह वास्तव में पूछे गए प्रश्न का उत्तर देता है।
CivFan

8

Kennytm के उत्तर में जोड़ना। जब आप एक उथली प्रति पेरेंट कॉपी करते हैं। () एक नया शब्दकोश एक ही कुंजी के साथ बनाया जाता है, लेकिन वे मान कॉपी नहीं किए जाते हैं जिन्हें संदर्भित किया जाता है। यदि आप parent_copy में एक नया मान जोड़ते हैं, तो यह पैरेंट को प्रभावित नहीं करेगा क्योंकि parent_copy एक नया शब्दकोश है। संदर्भ नहीं।

parent = {1: [1,2,3]}
parent_copy = parent.copy()
parent_reference = parent

print id(parent),id(parent_copy),id(parent_reference)
#140690938288400 140690938290536 140690938288400

print id(parent[1]),id(parent_copy[1]),id(parent_reference[1])
#140690938137128 140690938137128 140690938137128

parent_copy[1].append(4)
parent_copy[2] = ['new']

print parent, parent_copy, parent_reference
#{1: [1, 2, 3, 4]} {1: [1, 2, 3, 4], 2: ['new']} {1: [1, 2, 3, 4]}

के हैश (आईडी) मूल्य माता पिता [1] , parent_copy [1] समान हैं का तात्पर्य जो [1,2,3] के माता पिता [1] और parent_copy [1] आईडी 140690938288400 पर संग्रहीत।

लेकिन के हैश माता-पिता और parent_copy अलग है जिसका मतलब है वे विभिन्न शब्दकोशों हैं और parent_copy के मूल्यों को मान संदर्भ होने एक नया शब्दकोश है माता-पिता


5

"नया" और "मूल" अलग-अलग डाइट हैं, यही कारण है कि आप उनमें से सिर्फ एक को अपडेट कर सकते हैं .. आइटम उथले-कॉपी किए गए हैं, न कि खुद ही।


2

सामग्री उथले नकल कर रहे हैं।

इसलिए यदि मूल dictमें एक listया कोई अन्य है dictionary, तो उन्हें मूल या इसकी उथली प्रति में संशोधित करने से उन्हें ( listया dict) दूसरे में संशोधित किया जाएगा ।


1

अपने दूसरे भाग में, आपको उपयोग करना चाहिए new = original.copy()

.copyऔर =अलग चीजें हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.