जवाबों:
साथ new_list = my_list
, आप वास्तव में दो सूचियों जरूरत नहीं है। काम सिर्फ प्रतियां सूची के संदर्भ, न कि वास्तविक सूची, दोनों बहुत new_list
और my_list
काम के बाद एक ही सूची को देखें।
वास्तव में सूची की प्रतिलिपि बनाने के लिए, आपके पास विभिन्न संभावनाएं हैं:
आप बिलिन list.copy()
विधि का उपयोग कर सकते हैं (पायथन 3.3 के बाद से उपलब्ध):
new_list = old_list.copy()
आप इसे स्लाइस कर सकते हैं:
new_list = old_list[:]
इस बारे में एलेक्स मार्टेली की राय (कम से कम 2007 में ) यह है कि यह एक अजीब वाक्यविन्यास है और इसे कभी भी उपयोग करने का कोई मतलब नहीं है । ;) (उनकी राय में, अगले एक अधिक पठनीय है)।
आप अंतर्निहित list()
फ़ंक्शन का उपयोग कर सकते हैं :
new_list = list(old_list)
आप सामान्य उपयोग कर सकते हैं copy.copy()
:
import copy
new_list = copy.copy(old_list)
यह थोड़ा धीमा है list()
क्योंकि इसे old_list
पहले के डेटाटाइप का पता लगाना है ।
यदि सूची में ऑब्जेक्ट हैं और आप उन्हें भी कॉपी करना चाहते हैं, तो जेनेरिक का उपयोग करें copy.deepcopy()
:
import copy
new_list = copy.deepcopy(old_list)
स्पष्ट रूप से सबसे धीमी और सबसे स्मृति-आवश्यकता विधि, लेकिन कभी-कभी अपरिहार्य।
उदाहरण:
import copy
class Foo(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Foo({!r})'.format(self.val)
foo = Foo(1)
a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)
# edit orignal list and instance
a.append('baz')
foo.val = 5
print('original: %r\nlist.copy(): %r\nslice: %r\nlist(): %r\ncopy: %r\ndeepcopy: %r'
% (a, b, c, d, e, f))
परिणाम:
original: ['foo', Foo(5), 'baz']
list.copy(): ['foo', Foo(5)]
slice: ['foo', Foo(5)]
list(): ['foo', Foo(5)]
copy: ['foo', Foo(5)]
deepcopy: ['foo', Foo(1)]
फेलिक्स ने पहले से ही एक उत्कृष्ट जवाब दिया था, लेकिन मुझे लगा कि मैं विभिन्न तरीकों की गति की तुलना करूँगा:
copy.deepcopy(old_list)
Copy()
साथ कक्षाओं की नकल करने वाली शुद्ध अजगर विधिCopy()
विधि कक्षाओं की नकल नहीं (केवल डिक्सेस / लिस्ट / ट्यूपल्स)for item in old_list: new_list.append(item)
[i for i in old_list]
(एक सूची समझ )copy.copy(old_list)
list(old_list)
new_list = []; new_list.extend(old_list)
old_list[:]
( सूची टुकड़ा करने की क्रिया )तो सबसे तेज़ सूची स्लाइसिंग है। लेकिन ध्यान रखें कि copy.copy()
, list[:]
और list(list)
, इसके विपरीत copy.deepcopy()
और अजगर संस्करण सूची में किसी भी सूची, शब्दकोश और वर्ग उदाहरणों की नकल नहीं करते हैं, इसलिए यदि मूल बदल जाते हैं, तो वे प्रतिलिपि की गई सूची में भी बदल जाएंगे और इसके विपरीत।
(यहाँ स्क्रिप्ट है अगर किसी की दिलचस्पी है या किसी भी मुद्दे को उठाना चाहता है :)
from copy import deepcopy
class old_class:
def __init__(self):
self.blah = 'blah'
class new_class(object):
def __init__(self):
self.blah = 'blah'
dignore = {str: None, unicode: None, int: None, type(None): None}
def Copy(obj, use_deepcopy=True):
t = type(obj)
if t in (list, tuple):
if t == tuple:
# Convert to a list if a tuple to
# allow assigning to when copying
is_tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
if type(obj[x]) in dignore:
continue
obj[x] = Copy(obj[x], use_deepcopy)
if is_tuple:
# Convert back into a tuple again
obj = tuple(obj)
elif t == dict:
# Use the fast shallow dict copy() method and copy any
# values which aren't immutable (like lists, dicts etc)
obj = obj.copy()
for k in obj:
if type(obj[k]) in dignore:
continue
obj[k] = Copy(obj[k], use_deepcopy)
elif t in dignore:
# Numeric or string/unicode?
# It's immutable, so ignore it!
pass
elif use_deepcopy:
obj = deepcopy(obj)
return obj
if __name__ == '__main__':
import copy
from time import time
num_times = 100000
L = [None, 'blah', 1, 543.4532,
['foo'], ('bar',), {'blah': 'blah'},
old_class(), new_class()]
t = time()
for i in xrange(num_times):
Copy(L)
print 'Custom Copy:', time()-t
t = time()
for i in xrange(num_times):
Copy(L, use_deepcopy=False)
print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t
t = time()
for i in xrange(num_times):
copy.copy(L)
print 'copy.copy:', time()-t
t = time()
for i in xrange(num_times):
copy.deepcopy(L)
print 'copy.deepcopy:', time()-t
t = time()
for i in xrange(num_times):
L[:]
print 'list slicing [:]:', time()-t
t = time()
for i in xrange(num_times):
list(L)
print 'list(L):', time()-t
t = time()
for i in xrange(num_times):
[i for i in L]
print 'list expression(L):', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(L)
print 'list extend:', time()-t
t = time()
for i in xrange(num_times):
a = []
for y in L:
a.append(y)
print 'list append:', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(i for i in L)
print 'generator expression extend:', time()-t
timeit
मॉड्यूल का उपयोग करें । इसके अलावा, आप इस तरह के मनमाने माइक्रो बेंचमार्क से ज्यादा निष्कर्ष नहीं निकाल सकते हैं।
[*old_list]
तो यह लगभग बराबर होना चाहिए list(old_list)
, लेकिन चूंकि यह सिंटैक्स है, सामान्य फ़ंक्शन कॉल पथ नहीं है, इसलिए यह रनटाइम पर थोड़ा बचत करेगा (और इसके विपरीत old_list[:]
, जो टाइप नहीं करता है, [*old_list]
किसी भी चलने योग्य पर काम करता है और एक list
) पैदा करता है ।
timeit
, 100k के बजाय 50 मीटर रन) stackoverflow.com/a/43220129/3745896
[*old_list]
वास्तव में लगभग किसी अन्य विधि से बेहतर प्रदर्शन करता है। (पिछली टिप्पणियों में जुड़ा हुआ मेरा उत्तर देखें)
मुझे बताया गया है कि Python 3.3+ मेथड को जोड़ताlist.copy()
है, जो कि स्लाइसिंग जितना तेज़ होना चाहिए:
newlist = old_list.copy()
s.copy()
की उथली प्रति बनाता है । s
s[:]
python3.8
, .copy()
है थोड़ा तेजी से टुकड़ा करने की क्रिया से। नीचे देखें @AaronsHall जवाब।
पायथन में किसी सूची को क्लोन या कॉपी करने के विकल्प क्या हैं?
पायथन 3 में, एक उथली प्रति के साथ बनाया जा सकता है:
a_copy = a_list.copy()
पायथन 2 और 3 में, आप मूल के पूर्ण स्लाइस के साथ एक उथले प्रति प्राप्त कर सकते हैं:
a_copy = a_list[:]
किसी सूची को कॉपी करने के दो अर्थ तरीके हैं। उथली प्रति समान वस्तुओं की एक नई सूची बनाती है, एक गहरी प्रति एक नई सूची बनाती है जिसमें नई समतुल्य वस्तुएँ होती हैं।
उथली प्रतिलिपि केवल सूची को ही कॉपी करती है, जो सूची में वस्तुओं के संदर्भ में एक कंटेनर है। यदि स्वयं में समाहित वस्तुएं परिवर्तनशील हैं और एक को बदल दिया गया है, तो परिवर्तन दोनों सूचियों में परिलक्षित होगा।
पायथन 2 में ऐसा करने के अलग-अलग तरीके हैं और 3. पायथन 2 तरीके भी पायथन 3 में काम करेंगे।
पायथन 2 में, किसी सूची की उथली प्रतिलिपि बनाने का मुहावरेदार तरीका मूल के पूर्ण स्लाइस के साथ है:
a_copy = a_list[:]
आप सूची निर्माणकर्ता के माध्यम से सूची पास करके भी यही बात पूरी कर सकते हैं,
a_copy = list(a_list)
लेकिन निर्माणकर्ता का उपयोग करना कम कुशल है:
>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844
पायथन 3 में, सूचियों को list.copy
विधि मिलती है :
a_copy = a_list.copy()
पायथन 3.5 में:
>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125
New_list = my_list का उपयोग करना तब हर बार my_list परिवर्तन के लिए नए_सूची को संशोधित करता है। ऐसा क्यों है?
my_list
सिर्फ एक नाम है जो स्मृति में वास्तविक सूची की ओर इशारा करता है। जब आप कहते हैं कि new_list = my_list
आप प्रतिलिपि नहीं बना रहे हैं, तो आप स्मृति में उस मूल सूची में एक और नाम जोड़ रहे हैं। जब हम सूचियों की प्रतियां बनाते हैं तो हमारे पास समान मुद्दे हो सकते हैं।
>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]
सूची सामग्री की ओर संकेत करती है, इसलिए एक उथली प्रतिलिपि बस बिंदुओं को कॉपी करती है, और इसलिए आपके पास दो अलग-अलग सूचियाँ हैं, लेकिन उनके पास एक ही सामग्री है। सामग्री की प्रतियां बनाने के लिए, आपको एक गहरी प्रतिलिपि की आवश्यकता है।
किसी सूची की गहरी प्रतिलिपिdeepcopy
copy
बनाने के लिए, पायथन 2 या 3 में, मॉड्यूल में उपयोग करें :
import copy
a_deep_copy = copy.deepcopy(a_list)
यह प्रदर्शित करने के लिए कि यह हमें नई उप-सूची बनाने की अनुमति कैसे देता है:
>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]
और इसलिए हम देखते हैं कि गहरी कॉपी की गई सूची मूल से पूरी तरह से अलग सूची है। आप अपना स्वयं का फ़ंक्शन रोल कर सकते हैं - लेकिन नहीं। आपको मानक लाइब्रेरी के डीकोकोपी फ़ंक्शन का उपयोग करके अन्यथा बग न बनाने की संभावना है।
eval
आप इसे डीपेकॉपी करने के तरीके के रूप में उपयोग कर सकते हैं, लेकिन ऐसा न करें:
problematic_deep_copy = eval(repr(a_list))
64 बिट पायथन 2.7 में:
>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206
64 बिट पायथन 3.5 पर:
>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644
list_copy=[]
for item in list: list_copy.append(copy(item))
और यह बहुत तेज है।
पहले से ही कई उत्तर हैं जो आपको एक उचित प्रतिलिपि बनाने का तरीका बताते हैं, लेकिन उनमें से कोई भी नहीं कहता है कि आपकी मूल 'प्रतिलिपि' विफल क्यों हुई।
अजगर चर में मूल्यों को संग्रहीत नहीं करता है; यह वस्तुओं को नाम बांधता है। आपके मूल असाइनमेंट द्वारा निर्दिष्ट ऑब्जेक्ट को ले लिया my_list
और इसे भी बाध्य किया new_list
। कोई फर्क नहीं पड़ता कि आप किस नाम का उपयोग करते हैं, अभी भी केवल एक सूची है, इसलिए जब इसका उल्लेख किया जाता है तो इसे my_list
जारी रखने के दौरान किए गए परिवर्तन जारी रहेंगे new_list
। इस प्रश्न के अन्य उत्तरों में से प्रत्येक आपको बांधने के लिए एक नई वस्तु बनाने के विभिन्न तरीके देता है new_list
।
एक सूची का प्रत्येक तत्व एक नाम की तरह काम करता है, जिसमें प्रत्येक तत्व एक वस्तु के लिए गैर-अनन्य रूप से बांधता है। उथली प्रतिलिपि एक नई सूची बनाती है जिसके तत्व पहले की तरह ही वस्तुओं से बंधते हैं।
new_list = list(my_list) # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]
अपनी सूची को एक कदम आगे ले जाने के लिए, अपनी सूची को संदर्भित करने वाली प्रत्येक वस्तु को कॉपी करें, और उन तत्व प्रतियों को एक नई सूची में बांधें।
import copy
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]
यह अभी तक एक गहरी प्रतिलिपि नहीं है, क्योंकि सूची का प्रत्येक तत्व अन्य वस्तुओं को संदर्भित कर सकता है, जैसे सूची अपने तत्वों के लिए बाध्य है। सूची में प्रत्येक तत्व की पुनरावृत्ति करने के लिए, और फिर प्रत्येक तत्व द्वारा संदर्भित एक दूसरे ऑब्जेक्ट, और इसी तरह: एक गहरी प्रतिलिपि निष्पादित करें।
import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)
कॉपी करने में कोने के मामलों के बारे में अधिक जानकारी के लिए दस्तावेज़ देखें ।
उपयोग thing[:]
>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>>
आइए शुरुआत से शुरू करें और इस सवाल का पता लगाएं।
तो मान लीजिए कि आपके पास दो सूचियाँ हैं:
list_1=['01','98']
list_2=[['01','98']]
और हमें दोनों सूचियों को कॉपी करना होगा, जो अब पहली सूची से शुरू होती है:
तो पहले copy
हमारी मूल सूची में चर सेट करके कोशिश करते हैं list_1
:
copy=list_1
अब अगर आप list_1 की कॉपी की सोच रहे हैं, तो आप गलत हैं। id
समारोह दो चर एक ही वस्तु को इंगित कर सकते हैं अगर हमें दिखा सकते हैं। चलो यह करके देखें:
print(id(copy))
print(id(list_1))
आउटपुट है:
4329485320
4329485320
दोनों चर एक ही तर्क हैं। क्या आप आश्चर्यचकित हैं?
जैसा कि हम जानते हैं कि अजगर एक चर में कुछ भी संग्रहीत नहीं करता है, चर केवल वस्तु के लिए संदर्भित होते हैं और वस्तु मूल्य को संग्रहीत करते हैं। यहाँ ऑब्जेक्ट एक है, list
लेकिन हमने दो अलग-अलग वेरिएबल नामों से उसी ऑब्जेक्ट के दो संदर्भ बनाए हैं। इसका मतलब है कि दोनों चर एक ही वस्तु की ओर इशारा कर रहे हैं, बस अलग-अलग नामों से।
जब आप करते हैं copy=list_1
, यह वास्तव में कर रहा है:
यहाँ इमेज लिस्ट में १ और कॉपी दो वैरिएबल नाम हैं लेकिन ऑब्जेक्ट दोनों वैरिएबल के लिए समान है list
इसलिए यदि आप कॉपी की गई सूची को संशोधित करने का प्रयास करते हैं, तो यह मूल सूची को भी संशोधित करेगा क्योंकि सूची केवल एक ही है, आप उस सूची को संशोधित करेंगे चाहे आप कॉपी सूची से या मूल सूची से कोई फर्क नहीं पड़ता:
copy[0]="modify"
print(copy)
print(list_1)
उत्पादन:
['modify', '98']
['modify', '98']
इसलिए इसने मूल सूची को संशोधित किया:
अब चलो सूचियों की नकल करने के लिए एक पायथोनिक विधि पर चलते हैं।
copy_1=list_1[:]
यह विधि हमारे पास पहले समस्या को हल करती है:
print(id(copy_1))
print(id(list_1))
4338792136
4338791432
इसलिए जैसा कि हम अपनी दोनों सूची को अलग-अलग आईडी देख सकते हैं और इसका मतलब है कि दोनों चर अलग-अलग वस्तुओं की ओर इशारा कर रहे हैं। तो वास्तव में यहाँ क्या हो रहा है:
अब हम सूची को संशोधित करने का प्रयास करते हैं और देखते हैं कि क्या हम अभी भी पिछली समस्या का सामना कर रहे हैं:
copy_1[0]="modify"
print(list_1)
print(copy_1)
आउटपुट है:
['01', '98']
['modify', '98']
जैसा कि आप देख सकते हैं, यह केवल कॉपी की गई सूची को संशोधित करता है। इसका मतलब है कि यह काम किया।
क्या आपको लगता है कि हम कर चुके हैं? नहीं। हमारी नेस्टेड सूची को कॉपी करने का प्रयास करें।
copy_2=list_2[:]
list_2
किसी अन्य ऑब्जेक्ट का संदर्भ होना चाहिए जो की कॉपी है list_2
। चलो देखते है:
print(id((list_2)),id(copy_2))
हम उत्पादन प्राप्त:
4330403592 4330403528
अब हम मान सकते हैं कि दोनों सूचियाँ अलग-अलग ऑब्जेक्ट को इंगित कर रही हैं, इसलिए अब इसे संशोधित करने का प्रयास करें और देखते हैं कि यह वही दे रहा है जो हम चाहते हैं:
copy_2[0][1]="modify"
print(list_2,copy_2)
यह हमें आउटपुट देता है:
[['01', 'modify']] [['01', 'modify']]
यह थोड़ा भ्रमित करने वाला लग सकता है, क्योंकि वही तरीका जो हमने पहले इस्तेमाल किया था। आइए इसे समझने की कोशिश करते हैं।
जब तुम करोगे:
copy_2=list_2[:]
आप केवल बाहरी सूची की प्रतिलिपि बना रहे हैं, अंदर की सूची की नहीं। id
इसे जांचने के लिए हम एक बार फिर से फंक्शन का उपयोग कर सकते हैं ।
print(id(copy_2[0]))
print(id(list_2[0]))
आउटपुट है:
4329485832
4329485832
जब हम ऐसा करते हैं copy_2=list_2[:]
, तो ऐसा होता है:
यह सूची की प्रतिलिपि बनाता है, लेकिन केवल बाहरी सूची की प्रतिलिपि, नेस्टेड सूची की प्रतिलिपि नहीं, नेस्टेड सूची दोनों चर के लिए समान है, इसलिए यदि आप नेस्टेड सूची को संशोधित करने का प्रयास करते हैं तो यह मूल सूची को भी संशोधित करेगा क्योंकि नेस्टेड सूची ऑब्जेक्ट समान है दोनों सूचियों के लिए।
उपाय क्या है? समाधान deepcopy
कार्य है।
from copy import deepcopy
deep=deepcopy(list_2)
आइए इसकी जाँच करें:
print(id((list_2)),id(deep))
4322146056 4322148040
दोनों बाहरी सूचियों की अलग-अलग आईडी हैं, आइए आंतरिक नेस्टेड सूचियों पर प्रयास करें।
print(id(deep[0]))
print(id(list_2[0]))
आउटपुट है:
4322145992
4322145800
जैसा कि आप देख सकते हैं कि दोनों आईडी अलग-अलग हैं, जिसका अर्थ है कि हम मान सकते हैं कि दोनों नेस्टेड सूचियाँ अलग-अलग ऑब्जेक्ट को इंगित कर रही हैं।
इसका मतलब यह है कि जब आप deep=deepcopy(list_2)
वास्तव में क्या करते हैं :
दोनों नेस्टेड सूची अलग-अलग ऑब्जेक्ट को इंगित कर रही हैं और उनके पास अब नेस्टेड सूची की अलग-अलग कॉपी है।
अब नेस्टेड सूची को संशोधित करने की कोशिश करते हैं और देखते हैं कि क्या यह पिछले अंक को हल करता है या नहीं:
deep[0][1]="modify"
print(list_2,deep)
यह आउटपुट:
[['01', '98']] [['01', 'modify']]
जैसा कि आप देख सकते हैं, यह मूल नेस्टेड सूची को संशोधित नहीं किया था, यह केवल कॉपी की गई सूची को संशोधित करता है।
यहां Python 3.6.8 का उपयोग करते हुए समय के परिणाम हैं। ध्यान रखें ये समय एक दूसरे के सापेक्ष हैं, निरपेक्ष नहीं।
मैं केवल उथली प्रतियों को करने के लिए अटक गया, और कुछ नए तरीकों को भी जोड़ा, जो कि Python2 में संभव नहीं थे, जैसे कि list.copy()
(Python3 टुकड़ा समतुल्य ) और सूची के दो रूप अनपैकिंग ( *new_list, = list
और new_list = [*list]
):
METHOD TIME TAKEN
b = [*a] 2.75180600000021
b = a * 1 3.50215399999990
b = a[:] 3.78278899999986 # Python2 winner (see above)
b = a.copy() 4.20556500000020 # Python3 "slice equivalent" (see above)
b = []; b.extend(a) 4.68069800000012
b = a[0:len(a)] 6.84498999999959
*b, = a 7.54031799999984
b = list(a) 7.75815899999997
b = [i for i in a] 18.4886440000000
b = copy.copy(a) 18.8254879999999
b = []
for item in a:
b.append(item) 35.4729199999997
हम देख सकते हैं कि Python2 विजेता अभी भी अच्छा प्रदर्शन कर रहा है, लेकिन Python3 list.copy()
को बाहर नहीं निकाल पाता है, विशेष रूप से बाद की बेहतर पठनीयता को देखते हुए।
डार्क हॉर्स अनपैकिंग और रीपैकिंग विधि ( b = [*a]
) है, जो कच्चे स्लाइसिंग की तुलना में ~ 25% तेज है, और अन्य अनपैकिंग विधि ( *b, = a
) की तुलना में दोगुनी है ।
b = a * 1
आश्चर्यजनक रूप से अच्छा भी करता है।
ध्यान दें कि ये विधियाँ सूचियों के अलावा किसी भी इनपुट के लिए समान परिणाम का उत्पादन नहीं करती हैं। वे सभी काम करने योग्य वस्तुओं के लिए काम करते हैं, किसी भी चलने योग्य के लिए कुछ काम करते हैं, लेकिन केवल copy.copy()
अधिक सामान्य पायथन वस्तुओं के लिए काम करते हैं।
यहाँ इच्छुक पार्टियों के लिए परीक्षण कोड दिया गया है ( यहाँ से टेम्पलेट ):
import timeit
COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'
print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []; for item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a: b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))
b=[*a]
- यह करने का एक स्पष्ट तरीका;)।
अन्य सभी योगदानकर्ताओं ने बहुत अच्छे उत्तर दिए, जो तब काम करते हैं जब आपके पास एक एकल आयाम (समतल) सूची होती है, फिर भी अब तक बताए गए तरीकों में से, केवल copy.deepcopy()
एक सूची को कॉपी / कॉपी करने के लिए काम करता है और न कि list
जब आप होते हैं , तो यह नेस्टेड ऑब्जेक्ट को इंगित नहीं करता है। बहुआयामी, नेस्टेड सूचियों (सूचियों की सूची) के साथ काम करना। जबकि फेलिक्स क्लिंग ने अपने जवाब में इसे संदर्भित किया है, इस मुद्दे पर थोड़ा और अधिक है और संभवतः अंतर्निहित का उपयोग करके एक वर्कअराउंड है जो एक तेज विकल्प साबित हो सकता है deepcopy
।
हालांकि new_list = old_list[:]
, copy.copy(old_list)'
और old_list.copy()
एकल-स्तरीय सूचियों के लिए Py3k कार्य के लिए, वे list
ऑब्जेक्ट्स को इंगित करने के लिए वापस लौटते हैं, जो old_list
एंड-एंड के भीतर नेस्टेड हैं new_list
, और list
ऑब्जेक्ट्स में से एक में परिवर्तन दूसरे में स्थायी हैं।
जैसा कि आरोन हॉल और पीएम 2 रिंग द्वारा बताया गया है, इसका उपयोग
eval()
करना न केवल एक बुरा विचार है, बल्कि यह बहुत धीमा भी हैcopy.deepcopy()
।इसका मतलब है कि बहुआयामी सूचियों के लिए, एकमात्र विकल्प है
copy.deepcopy()
। कहा जा रहा है कि, यह वास्तव में एक विकल्प नहीं है क्योंकि जब आप मध्यम आकार के बहुआयामी सरणी पर इसका उपयोग करने का प्रयास करते हैं तो प्रदर्शन दक्षिण की ओर जाता है। मैंनेtimeit
एक 42x42 सरणी का उपयोग करने की कोशिश की , न कि अनसुनी या यहां तक कि जैव सूचना विज्ञान अनुप्रयोगों के लिए बड़ी, और मैंने प्रतिक्रिया की प्रतीक्षा में छोड़ दिया और बस इस पोस्ट पर अपना संपादन लिखना शुरू कर दिया।ऐसा लगता है कि एकमात्र वास्तविक विकल्प तब कई सूचियों को शुरू करना और उन पर स्वतंत्र रूप से काम करना है। अगर किसी के पास बहुआयामी सूची की नकल को संभालने के लिए कोई अन्य सुझाव हैं, तो इसकी सराहना की जाएगी।
जैसा कि दूसरों ने कहा है, मॉड्यूल का उपयोग करते हुए और बहुआयामी सूचियों के लिए महत्वपूर्ण प्रदर्शन मुद्दे हैं ।copy
copy.deepcopy
repr()
ऑब्जेक्ट को फिर से बनाने के लिए पर्याप्त है। इसके अलावा, eval()
अंतिम उपाय का एक उपकरण है; देखें Eval वास्तव में खतरनाक है जानकारी के लिए इतना अनुभवी नेड Batchelder द्वारा। इसलिए जब आप उपयोग की वकालत करते हैं eval()
तो आपको वास्तव में उल्लेख करना चाहिए कि यह खतरनाक हो सकता है।
eval()
सामान्य रूप से पायथन में कार्य करना एक जोखिम है। यह इतना नहीं है कि आप कोड में फ़ंक्शन का उपयोग करते हैं या नहीं, लेकिन यह पायथन में और अपने आप में एक सुरक्षा छेद है। मेरे उदाहरण इसे प्रयोग नहीं कर रहा है एक समारोह है कि से इनपुट प्राप्त के साथ input()
, sys.agrv
या यहां तक कि एक पाठ फ़ाइल। यह एक बार एक रिक्त बहुआयामी सूची को आरम्भ करने की पंक्तियों के साथ अधिक है, और फिर लूप के प्रत्येक पुनरावृत्ति पर पुन: स्थापित करने के बजाय इसे लूप में कॉपी करने का एक तरीका है।
new_list = eval(repr(old_list))
, इसलिए इसके अलावा यह एक बुरा विचार है, यह संभवतः काम करने के लिए बहुत धीमा भी है।
मुझे आश्चर्य है कि यह अभी तक उल्लेख नहीं किया गया है, इसलिए पूर्णता के लिए ...
आप "स्पैट ऑपरेटर" के साथ सूची अनपैकिंग कर सकते हैं: *
जो आपकी सूची के तत्वों को भी कॉपी करेगा।
old_list = [1, 2, 3]
new_list = [*old_list]
new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]
इस विधि के लिए स्पष्ट नकारात्मक यह है कि यह केवल पायथन 3.5+ में उपलब्ध है।
हालांकि समय के अनुसार, यह अन्य सामान्य तरीकों की तुलना में बेहतर प्रदर्शन करता है।
x = [random.random() for _ in range(1000)]
%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]
%timeit a = [*x]
#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
old_list
और new_list
दो अलग-अलग सूचियां हैं, एक संपादन दूसरे को नहीं बदलेगा (जब तक कि आप सीधे तत्वों को स्वयं उत्परिवर्तित न करें (जैसे सूची की सूची), इनमें से कोई भी विधि गहरी प्रतियां नहीं हैं)।
अजगर संस्करण से स्वतंत्र एक बहुत ही सरल दृष्टिकोण पहले से दिए गए जवाबों में गायब था जिसे आप ज्यादातर समय का उपयोग कर सकते हैं (कम से कम मैं ऐसा करता हूं):
new_list = my_list * 1 #Solution 1 when you are not using nested lists
हालाँकि, यदि my_list में अन्य कंटेनर (उदाहरण के लिए नेस्टेड सूचियाँ) हैं, तो आपको डीपकोपी का उपयोग करना होगा, क्योंकि अन्य लोगों ने कॉपी लाइब्रेरी से ऊपर दिए गए उत्तर में सुझाव दिया था। उदाहरण के लिए:
import copy
new_list = copy.deepcopy(my_list) #Solution 2 when you are using nested lists
। बोनस : यदि आप तत्वों के उपयोग की प्रतिलिपि नहीं बनाना चाहते हैं (उर्फ उथले प्रति):
new_list = my_list[:]
आइए समाधान # 1 और समाधान # 2 के बीच अंतर को समझते हैं
>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])
जैसा कि आप देख सकते हैं समाधान # 1 पूरी तरह से काम किया जब हम नेस्टेड सूचियों का उपयोग नहीं कर रहे थे। आइए देखें कि क्या होगा जब हम समाधान # 1 से नेस्टेड सूचियों पर लागू होते हैं।
>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]] #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]] #Solution #2 - DeepCopy worked in nested list
ध्यान दें कि कुछ ऐसे मामले हैं जहाँ अगर आपने अपनी खुद की कस्टम क्लास को परिभाषित किया है और आप विशेषताओं को रखना चाहते हैं तो आपको विकल्प के बजाय copy.copy()
या उपयोग करना चाहिए copy.deepcopy()
, उदाहरण के लिए पायथन 3:
import copy
class MyList(list):
pass
lst = MyList([1,2,3])
lst.name = 'custom list'
d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}
for k,v in d.items():
print('lst: {}'.format(k), end=', ')
try:
name = v.name
except AttributeError:
name = 'NA'
print('name: {}'.format(name))
आउटपुट:
lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
new_list = my_list[:]
new_list = my_list
इसे समझने की कोशिश करें। मान लेते हैं कि my_list X स्थान पर ढेर मेमोरी में है अर्थात my_list X को इंगित कर रहा है। अब असाइन करके new_list = my_list
आप X को इंगित करने वाले new_list को बता रहे हैं। इसे उथली प्रतिलिपि के रूप में जाना जाता है।
अब यदि आप असाइन करते हैं तो आप new_list = my_list[:]
my_list के प्रत्येक ऑब्जेक्ट को new_list में कॉपी कर रहे हैं। इसे डीप कॉपी के रूप में जाना जाता है।
दूसरा तरीका यह कर सकते हैं:
new_list = list(old_list)
import copy
new_list = copy.deepcopy(old_list)
मैं कुछ अलग पोस्ट करना चाहता था तो कुछ अन्य उत्तर। भले ही यह सबसे अधिक समझने योग्य या सबसे तेज़ विकल्प न होने की संभावना है, लेकिन यह अंदर का एक दृश्य प्रदान करता है कि कितनी गहरी प्रतिलिपि काम करती है, साथ ही गहरी नकल के लिए एक और वैकल्पिक विकल्प है। यह वास्तव में मायने नहीं रखता है अगर मेरे फ़ंक्शन में बग हैं, क्योंकि इस बिंदु को प्रश्न के उत्तर जैसी वस्तुओं की प्रतिलिपि बनाने का एक तरीका दिखाना है, लेकिन यह भी एक बिंदु के रूप में इसका उपयोग यह समझाने के लिए है कि डीपॉस्कोपी इसके मूल में कैसे काम करता है।
किसी भी गहरी प्रतिलिपि समारोह के मूल में एक उथले प्रतिलिपि बनाने का तरीका है। कैसे? सरल। कोई भी गहरी प्रतिलिपि फ़ंक्शन केवल अपरिवर्तनीय वस्तुओं के कंटेनरों को डुप्लिकेट करता है। जब आप एक नेस्टेड सूची को गहरा करते हैं, तो आप केवल बाहरी सूचियों की नकल कर रहे हैं, न कि सूचियों के अंदर की परस्पर वस्तुओं की। आप केवल कंटेनरों की नकल कर रहे हैं। कक्षाओं के लिए भी यही काम करता है। जब आप किसी वर्ग को डीपकोपी करते हैं, तो आप उसके सभी उत्परिवर्तनीय गुणों को डीपकोपी करते हैं। तो कैसे? कैसे आप केवल कंटेनरों को कॉपी करने के लिए आते हैं, जैसे कि सूचियां, डिक्सेस, ट्यूपल्स, इटर्स, क्लासेस और क्लास इंस्टेंसेस?
यह आसान है। एक उत्परिवर्तित वस्तु को वास्तव में डुप्लिकेट नहीं किया जा सकता है। इसे कभी नहीं बदला जा सकता है, इसलिए यह केवल एक मूल्य है। इसका मतलब है कि आपको कभी भी स्ट्रिंग्स, नंबरों, बूल्स या उनमें से किसी को भी डुप्लिकेट नहीं करना है। लेकिन आप कंटेनरों की नकल कैसे करेंगे? सरल। आप सभी मानों के साथ एक नया कंटेनर आरंभ करें। डीपस्कोपी पुनरावर्तन पर निर्भर करता है। यह सभी कंटेनरों को डुप्लिकेट करता है, यहां तक कि उनके अंदर के कंटेनरों के साथ भी, जब तक कोई कंटेनर नहीं बचा है। एक कंटेनर एक अपरिवर्तनीय वस्तु है।
एक बार जब आप जानते हैं कि, किसी भी संदर्भ के बिना किसी ऑब्जेक्ट को पूरी तरह से डुप्लिकेट करना बहुत आसान है। यहां बुनियादी डेटा-प्रकारों को डीपकोप करने के लिए एक फ़ंक्शन है (कस्टम कक्षाओं के लिए काम नहीं करेगा लेकिन आप हमेशा इसे जोड़ सकते हैं)
def deepcopy(x):
immutables = (str, int, bool, float)
mutables = (list, dict, tuple)
if isinstance(x, immutables):
return x
elif isinstance(x, mutables):
if isinstance(x, tuple):
return tuple(deepcopy(list(x)))
elif isinstance(x, list):
return [deepcopy(y) for y in x]
elif isinstance(x, dict):
values = [deepcopy(y) for y in list(x.values())]
keys = list(x.keys())
return dict(zip(keys, values))
पाइथन की अपनी अंतर्निहित डीकोस्कोपी उस उदाहरण के आसपास आधारित है। एकमात्र अंतर यह है कि यह अन्य प्रकारों का समर्थन करता है, और एक नए डुप्लिकेट वर्ग में विशेषताओं को डुप्लिकेट करके उपयोगकर्ता-कक्षाओं का भी समर्थन करता है, और एक वस्तु के संदर्भ के साथ अनंत-पुनरावृत्ति को भी रोकता है जो पहले से ही मेमो सूची या शब्दकोश का उपयोग करके देखा जाता है। और यह वास्तव में गहरी प्रतियां बनाने के लिए है। इसके मूल में, एक गहरी प्रतिलिपि बनाना केवल उथली प्रतियां बनाना है। मुझे आशा है कि यह उत्तर प्रश्न में कुछ जोड़ता है।
उदाहरण
मान लें कि आपके पास यह सूची है: [1, 2, 3] । अपरिवर्तनीय संख्याओं को डुप्लिकेट नहीं किया जा सकता है, लेकिन दूसरी परत कर सकते हैं। आप एक सूची समझ का उपयोग करके इसे डुप्लिकेट कर सकते हैं: [1, 2, 3 में x के लिए x]
अब, कल्पना कीजिए कि आपके पास यह सूची है: [[1, 2], [3, 4], [5, 6]] । इस बार, आप एक फ़ंक्शन बनाना चाहते हैं, जो सूची की सभी परतों की गहरी प्रतिलिपि बनाने के लिए पुनरावृत्ति का उपयोग करता है। पिछली सूची की बजाय समझ:
[x for x in _list]
यह सूचियों के लिए एक नया प्रयोग करता है:
[deepcopy_list(x) for x in _list]
और deepcopy_list इस तरह दिखता है:
def deepcopy_list(x):
if isinstance(x, (str, bool, float, int)):
return x
else:
return [deepcopy_list(y) for y in x]
फिर अब आपके पास एक फ़ंक्शन है जो strs, bools, floast, ints और यहां तक कि सूचियों की किसी भी सूची को पुनर्संरचना का उपयोग करके अनंत रूप से सूचीबद्ध कर सकता है। और वहां आपके पास है, डीपकोपिंग।
TLDR : डीपस्कोपी वस्तुओं को डुप्लिकेट करने के लिए पुनरावृत्ति का उपयोग करता है, और केवल वही अपरिवर्तनीय वस्तुओं को पहले की तरह वापस करता है, क्योंकि अपरिवर्तनीय वस्तुओं को डुप्लिकेट नहीं किया जा सकता है। हालाँकि, यह उत्परिवर्तित वस्तुओं की सबसे भीतरी परतों को तब तक गहरा करता है जब तक कि यह किसी वस्तु की सबसे बाहरी उत्परिवर्तित परत तक नहीं पहुँच जाती।
आईडी और जीसी के माध्यम से स्मृति में देखने के लिए एक मामूली व्यावहारिक दृष्टिकोण।
>>> b = a = ['hell', 'word']
>>> c = ['hell', 'word']
>>> id(a), id(b), id(c)
(4424020872, 4424020872, 4423979272)
| |
-----------
>>> id(a[0]), id(b[0]), id(c[0])
(4424018328, 4424018328, 4424018328) # all referring to same 'hell'
| | |
-----------------------
>>> id(a[0][0]), id(b[0][0]), id(c[0][0])
(4422785208, 4422785208, 4422785208) # all referring to same 'h'
| | |
-----------------------
>>> a[0] += 'o'
>>> a,b,c
(['hello', 'word'], ['hello', 'word'], ['hell', 'word']) # b changed too
>>> id(a[0]), id(b[0]), id(c[0])
(4424018384, 4424018384, 4424018328) # augmented assignment changed a[0],b[0]
| |
-----------
>>> b = a = ['hell', 'word']
>>> id(a[0]), id(b[0]), id(c[0])
(4424018328, 4424018328, 4424018328) # the same hell
| | |
-----------------------
>>> import gc
>>> gc.get_referrers(a[0])
[['hell', 'word'], ['hell', 'word']] # one copy belong to a,b, the another for c
>>> gc.get_referrers(('hell'))
[['hell', 'word'], ['hell', 'word'], ('hell', None)] # ('hello', None)
याद रखें कि पायथन जब आप करते हैं:
list1 = ['apples','bananas','pineapples']
list2 = list1
List2 वास्तविक सूची को संग्रहीत नहीं कर रहा है, लेकिन सूची 1 का संदर्भ है। तो जब आप list1 के लिए कुछ भी करते हैं, तो list2 भी बदल जाता है। सूची की मूल प्रतिलिपि ( नेस्टेड लोगों के लिए copy.copy()
, सरल सूचियों के लिए ) बनाने के लिए कॉपी मॉड्यूल (डिफ़ॉल्ट रूप से, पाइप पर डाउनलोड नहीं copy.deepcopy()
) का उपयोग करें। यह एक ऐसी प्रति बनाता है जो पहली सूची के साथ नहीं बदलती है।
Deepcopy विकल्प एकमात्र तरीका है जो मेरे लिए काम करता है:
from copy import deepcopy
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = deepcopy(a)
b[0][1]=[3]
print('Deep:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a*1
b[0][1]=[3]
print('*1:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a[:]
b[0][1]=[3]
print('Vector copy:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = list(a)
b[0][1]=[3]
print('List copy:')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a.copy()
b[0][1]=[3]
print('.copy():')
print(a)
print(b)
print('-----------------------------')
a = [ [ list(range(1, 3)) for i in range(3) ] ]
b = a
b[0][1]=[3]
print('Shallow:')
print(a)
print(b)
print('-----------------------------')
के उत्पादन की ओर जाता है:
Deep:
[[[1, 2], [1, 2], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
*1:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Vector copy:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
List copy:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
.copy():
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
Shallow:
[[[1, 2], [3], [1, 2]]]
[[[1, 2], [3], [1, 2]]]
-----------------------------
newlist = [*mylist]
पायथन में भी एक संभावना है 3.newlist = list(mylist)
हालांकि अधिक स्पष्ट है।