2013-09-28 4 views
9

official Python docs कहता है कि स्लाइसिंग ऑपरेटर का उपयोग करके और पायथन में असाइन करने से कटा हुआ सूची की उथली प्रतिलिपि बन जाती है।क्या एक टुकड़ा करने वाला ऑपरेशन मुझे गहरी या उथली प्रतिलिपि देता है?

लेकिन जब मैं उदाहरण के लिए कोड लिखने:

o = [1, 2, 4, 5] 
p = o[:] 

और जब मैं लिखने:

id(o) 
id(p) 

मैं अलग पहचान-पत्र प्राप्त है और यह भी एक के बाद एक सूची जोड़कर अन्य सूची में प्रतिबिंबित नहीं करता। क्या यह एक गहरी प्रतिलिपि नहीं बना रहा है या कहीं कहीं मैं गलत हो रहा हूं?

उत्तर

14

आप उथले प्रतिलिपि बना रहे हैं, क्योंकि नेस्टेड मानों की प्रतिलिपि बनाई गई है, केवल संदर्भित है। गहरी प्रति सूची द्वारा संदर्भित मानों की प्रतियां भी बनाएगी।

डेमो:

>>> lst = [{}] 
>>> lst_copy = lst[:] 
>>> lst_copy[0]['foo'] = 'bar' 
>>> lst_copy.append(42) 
>>> lst 
[{'foo': 'bar'}] 
>>> id(lst) == id(lst_copy) 
False 
>>> id(lst[0]) == id(lst_copy[0]) 
True 

यहाँ नेस्टेड शब्दकोश कॉपी नहीं है; यह केवल दोनों सूचियों द्वारा संदर्भित है। नया तत्व 42 साझा नहीं किया गया है।

याद रखें कि पायथन में सब कुछ एक वस्तु है, और नाम और सूची तत्व केवल उन वस्तुओं के संदर्भ हैं। किसी सूची की एक प्रति नई बाहरी सूची बनाता है, लेकिन नई सूची केवल सटीक वही ऑब्जेक्ट्स के संदर्भ प्राप्त करती है।

>>> from copy import deepcopy 
>>> lst_deepcopy = deepcopy(lst) 
>>> id(lst_deepcopy[0]) == id(lst[0]) 
False 
+0

तो मुझे अलग-अलग आईडी – user2528042

+1

@ user2528042 क्यों मिल रहा है: क्योंकि * बाहरी सूची ऑब्जेक्ट्स * समान नहीं हैं। –

+0

@ user2528042 क्योंकि मूल सूची * की प्रतिलिपि बनाई गई है * एक नई वस्तु पर। केवल सभी तत्वों की प्रतिलिपि बनाई गई नहीं है, इसलिए यदि सूची में एक म्यूटेबल ऑब्जेक्ट (इन्ट्स म्यूटेबल नहीं हैं) बदलते हैं तो उस ऑब्जेक्ट को मूल और कॉपी की गई सूची दोनों में बदल दिया जाएगा क्योंकि दोनों में एक ही ऑब्जेक्ट के संदर्भ की एक प्रति है। – poke

5

आपको पता होना चाहिए कि is या id का उपयोग कर परीक्षण है कि क्या एक सत्य प्रतिलिपि बनाई जा रही है की भ्रामक हो सकता है:

एक उचित गहरी प्रतिलिपि प्रत्येक के नए प्रतियां और हर वस्तु सूची में निहित, रिकर्सिवली बनाता है अपरिवर्तनीय और interned ऑब्जेक्ट्स जैसे तार, पूर्णांक और टुपल्स के साथ अपरिवर्तनीय होते हैं।

>>> l1=['one'] 
>>> l2=['one'] 
>>> l1 is l2 
False 
>>> l1[0] is l2[0] 
True 

अब l1 की एक उथले प्रतिलिपि बनाने और अपरिवर्तनीय स्ट्रिंग का परीक्षण:

>>> l3=l1[:] 
>>> l3 is l1 
False 
>>> l3[0] is l1[0] 
True 

अब l1[0] द्वारा निहित स्ट्रिंग की एक प्रतिलिपि बनाने

एक आसानी से प्रशिक्षु तार के उदाहरण से समझ पर विचार करें :

>>> s1=l1[0][:] 
>>> s1 
'one' 
>>> s1 is l1[0] is l2[0] is l3[0] 
True    # they are all the same object 

टी ry एक deepcopy जहां हर तत्व की नकल की जानी चाहिए:

>>> from copy import deepcopy 
>>> l4=deepcopy(l1) 
>>> l4[0] is l1[0] 
True 

प्रत्येक मामले में, स्ट्रिंग 'one' अपरिवर्तनीय तार और is की पायथन के आंतरिक कैश में प्रशिक्षु की जा रही है कि वे एक ही कर रहे हैं (वे एक ही id है) दिखाई देगा । यह कार्यान्वयन और संस्करण है जो आंतरिक रूप से प्राप्त होता है और जब ऐसा होता है, तो आप इस पर निर्भर नहीं हो सकते हैं। यह एक पर्याप्त स्मृति और प्रदर्शन वृद्धि हो सकती है।

आप एक उदाहरण है कि तुरन्त प्रशिक्षु नहीं हो मजबूर कर सकते हैं: अगर पाया गया कि स्ट्रिंग कैश की गई वस्तु का उल्लेख करने के कारण होने की पायथन intern function

>>> s2=''.join(c for c in 'one') 
>>> s2==l1[0] 
True 
>>> s2 is l1[0] 
False 

और फिर आप उपयोग कर सकते हैं:

>>> l1[0] is s2 
False 
>>> s2=intern(s2) 
>>> l1[0] is s2 
True 

ही immutables की tuples पर लागू होता है:

>>> t1=('one','two') 
>>> t2=t1[:] 
>>> t1 is t2 
True 
>>> t3=deepcopy(t1) 
>>> t3 is t2 is t1 
True 

एक immutables (पूर्णांकों की तरह) के घ परिवर्तनशील सूचियों सूची के सदस्य दफनाया हो सकता है:

>>> li1=[1,2,3] 
>>> li2=deepcopy(li1) 
>>> li2 == li1 
True 
>>> li2 is li1 
False 
>>> li1[0] is li2[0] 
True 

तो तुम अजगर कार्य है कि आप जानते हैं, लेकिन अंतिम परिणाम कुछ कॉपी जाएगा एक प्रशिक्षु अपरिवर्तनीय वस्तु के लिए एक और संदर्भ है का उपयोग कर सकते हैं। is परीक्षण एक प्रतिलिपि बनाने का केवल एक डिस्पोजेक्टिव परीक्षण है यदि आइटम म्यूटेबल हैं।

+0

पायथन 3 पर, 'intern' को' sys' मॉड्यूल में ले जाया गया है, इसलिए आपको 'आयात sys' करने की आवश्यकता है; एस = sys.intern (रों) ' – dawg

संबंधित मुद्दे