কীভাবে একটি তালিকা ক্লোন বা অনুলিপি করবেন?


2543

পাইথনে কোনও তালিকা ক্লোন বা অনুলিপি করার বিকল্পগুলি কী কী?

ব্যবহারের সময় new_list = my_list, প্রতিবার new_listপরিবর্তিত যেকোন পরিবর্তন my_list। কেন?

উত্তর:


3319

সহ new_list = my_list, আপনার কাছে আসলে দুটি তালিকা নেই। অ্যাসাইনমেন্টটি কেবলমাত্র তালিকার রেফারেন্সটি অনুলিপি করে, প্রকৃত তালিকা নয়, সুতরাং উভয়ই new_listএবং my_listনিয়োগের পরে একই তালিকাটি উল্লেখ করে।

প্রকৃতপক্ষে তালিকাটি অনুলিপি করতে আপনার বিভিন্ন সম্ভাবনা রয়েছে:

  • আপনি বিল্টিন list.copy()পদ্ধতিটি ব্যবহার করতে পারেন (পাইথন ৩.৩ থেকে পাওয়া যায়):

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

7
যদি আমি ভুল করছি না: newlist = [*mylist]পাইথন 3 এও একটি সম্ভাবনা maybe newlist = list(mylist)সম্ভবত যদিও এটি আরও স্পষ্ট।
স্টাফেন

9
অন্য সম্ভাবনা new_list = old_list * 1
এআরআইএস

4
এই পদ্ধতিগুলির মধ্যে কোনটি অগভীর অনুলিপি এবং কোনটি গভীর অনুলিপি?
এশ্বর

4
@ Warশ্বর: শেষটি বাদে সমস্ত একটি অগভীর অনুলিপি করেন
ফেলিক্স ক্লিং

3
@ ইশ্বর এটি একটি অগভীর অনুলিপি।
juanpa.arrivillaga

602

ফেলিক্স ইতিমধ্যে একটি দুর্দান্ত উত্তর সরবরাহ করেছে, তবে আমি ভেবেছিলাম যে আমি বিভিন্ন পদ্ধতির সাথে একটি গতি তুলনা করব:

  1. 10.59 সেকেন্ড (105.9us / itn) - copy.deepcopy(old_list)
  2. 10.16 সেকেন্ড (101.6us / itn) - খাঁটি পাইথন Copy()পদ্ধতি ডিপকপি দিয়ে ক্লাস অনুলিপি করছে
  3. 1.488 সেকেন্ড (14.88us / itn) - খাঁটি পাইথন Copy()পদ্ধতি ক্লাস অনুলিপি করছে না (কেবলমাত্র dicts / list / tuples)
  4. 0.325 সেকেন্ড (3.25us / itn) - for item in old_list: new_list.append(item)
  5. 0.217 সেকেন্ড (2.17us / itn) - [i for i in old_list](একটি তালিকা বোঝার জন্য )
  6. 0.186 সেকেন্ড (1.86us / itn) - copy.copy(old_list)
  7. 0.075 সেকেন্ড (0.75us / itn) - list(old_list)
  8. 0.053 সেকেন্ড (0.53us / itn) - new_list = []; new_list.extend(old_list)
  9. 0,039 সেকেন্ড (0.39us / ITN) - old_list[:]( তালিকা slicing )

দ্রুততম তালিকার কাটা তালিকা। কিন্তু যে সচেতন হতে 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

9
যেহেতু আপনি বেঞ্চমার্কিং করছেন তাই এটি একটি রেফারেন্স পয়েন্ট অন্তর্ভুক্ত করা সহায়ক হতে পারে। এই পরিসংখ্যানগুলি কি এখনও সম্পূর্ণ সংকলিত কোড সহ পাইথন 3.6 ব্যবহার করে সঠিক? আমি নীচের উত্তরটি লক্ষ্য করছি ( স্ট্যাকওভারফ্লো.com / a / 17810305 / 26219 ) ইতিমধ্যে এই উত্তরটিকে প্রশ্ন করে।
মার্ক এডিংটন

4
timeitমডিউল ব্যবহার করুন । এছাড়াও, আপনি এ জাতীয় নির্বিচারে মাইক্রো বেনমার্ক থেকে অনেক উপসংহার করতে পারবেন না।
কোরি গোল্ডবার্গ

3
আপনি যদি 3.5++ এর জন্য একটি নতুন বিকল্প অন্তর্ভুক্ত করতে চান তবে এটি [*old_list]মোটামুটি সমতুল্য হওয়া উচিত list(old_list), তবে এটি সিনট্যাক্স, সাধারণ ফাংশন কল পথ নয়, এটি রানটাইমের সময় কিছুটা সাশ্রয় করবে (এবং এর বিপরীতে old_list[:]যা রূপান্তর টাইপ করে না, [*old_list]যে কোনও পুনরাবৃত্তির উপর কাজ করে এবং উত্পাদন করে a list)।
ShadowRanger

3
@ কোরিগল্ডবার্গ সামান্য কম স্বেচ্ছাচারী মাইক্রো-বেঞ্চমার্কের জন্য (ব্যবহার করুন timeit, 100 কে এর পরিবর্তে 50 মি রান) স্ট্যাকওভারফ্লো
নদী

1
@ শ্যাডোএ্যাঞ্জার [*old_list]আসলে অন্য যে কোনও পদ্ধতিকে ছাড়িয়ে গেছে বলে মনে হচ্ছে। (আমার পূর্ববর্তী মন্তব্যে
নদী

150

আমি করেছি বলা হয়েছে যে পাইথন 3.3+ যোগlist.copy() পদ্ধতি, যা slicing মতোই কি দুদ্দাড় করে হওয়া উচিত:

newlist = old_list.copy()


6
হ্যাঁ, এবং ডকস অনুসারে ডকস.পিথন.আর.৩ / ৩ / লাইব্রেরি / স্টাডিটিপস html # পরিবর্তনযোগ্য- সিক্যুয়েন্স-টাইপগুলি (একই হিসাবে ) এর s.copy()অগভীর অনুলিপি তৈরি করে । ss[:]
সাইবারমিউ

আসলে মনে হচ্ছে যে বর্তমানে python3.8, .copy()হয় সামান্য দ্রুত slicing হয়। নীচে @ অ্যারোনশাল উত্তর দেখুন।
প্রিয়.বি। জেসুস

125

পাইথনে কোনও তালিকা ক্লোন বা অনুলিপি করার বিকল্পগুলি কী কী?

পাইথন 3 এ, অগভীর অনুলিপিটি দিয়ে তৈরি করা যেতে পারে:

a_copy = a_list.copy()

পাইথন 2 এবং 3 এ, আপনি মূলটির সম্পূর্ণ টুকরো দিয়ে অগভীর অনুলিপিটি পেতে পারেন:

a_copy = a_list[:]

ব্যাখ্যা

তালিকাটি অনুলিপি করার দুটি উপায় রয়েছে। অগভীর অনুলিপি একই জিনিসগুলির একটি নতুন তালিকা তৈরি করে, একটি গভীর অনুলিপি নতুন সমতুল্য অবজেক্টযুক্ত একটি নতুন তালিকা তৈরি করে।

অগভীর তালিকার অনুলিপি

অগভীর অনুলিপি কেবল তালিকার অনুলিপি করে, যা তালিকার অবজেক্টগুলির রেফারেন্সের ধারক। যদি নিজের মধ্যে থাকা অবজেক্টগুলি পরিবর্তনীয় হয় এবং একটিতে পরিবর্তন হয় তবে পরিবর্তনটি উভয় তালিকায় প্রতিফলিত হবে।

পাইথন 2 এবং 3 এ করার বিভিন্ন উপায় রয়েছে পাইথন 2 উপায় পাইথন 3 তেও কাজ করবে।

পাইথন 2

পাইথন 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

অন্য পয়েন্টার তৈরি করা অনুলিপি তৈরি করে না

নতুন_লিস্ট = আমার_লিস্ট ব্যবহার করে প্রতিবার আমার_লিস্ট পরিবর্তিত হলে নতুন তালিকা পরিবর্তন করে। কেন?

my_listকেবলমাত্র একটি নাম যা স্মৃতিতে প্রকৃত তালিকার দিকে নির্দেশ করে। যখন আপনি বলেন যে new_list = my_listআপনি অনুলিপি তৈরি করছেন না, আপনি কেবলমাত্র আরেকটি নাম যুক্ত করছেন যা মেমরির সেই মূল তালিকায় নির্দেশ করে। তালিকার কপিগুলি তৈরি করার সময় আমরা একই রকম সমস্যা থাকতে পারি।

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

তালিকাগুলি কেবলমাত্র পয়েন্টারগুলির একটি অ্যারে, সুতরাং একটি অগভীর অনুলিপি কেবল পয়েন্টারগুলি অনুলিপি করে এবং সুতরাং আপনার দুটি পৃথক তালিকা রয়েছে, তবে তাদের একই বিষয়বস্তু রয়েছে। সামগ্রীর অনুলিপি তৈরি করতে আপনার একটি গভীর অনুলিপি দরকার।

গভীর কপি

একটি তৈরি করতে হলে পাইথন 2 অথবা 3 একটি তালিকার গভীর অনুলিপি, ব্যবহার deepcopyমধ্যে copyমডিউল :

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))
  1. এটি বিপজ্জনক, বিশেষত যদি আপনি এমন কোনও উত্স থেকে বিশ্বাস করেন না যে কোনও জিনিস থেকে মূল্যায়ন করছেন।
  2. এটি নির্ভরযোগ্য নয়, যদি আপনি অনুলিপি করছেন এমন কোনও অত্যাবসায়ীটির একটি উপস্থাপনা না থাকে যা সমতুল্য উপাদানটির পুনরুত্পাদন করতে পারে।
  3. এটিও কম পারফরম্যান্ট।

Bit৪ বিট পাইথন ২.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

bit৪ বিট পাইথন 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

1
তালিকাটি 2 ডি হলে আপনার ডিপকপি দরকার নেই। যদি এটি তালিকার একটি তালিকা হয় এবং সেই তালিকাগুলির মধ্যে তালিকা না থাকে তবে আপনি লুপের জন্য একটি ব্যবহার করতে পারেন। বর্তমানে, আমি ব্যবহার করছি list_copy=[] for item in list: list_copy.append(copy(item))এবং এটি আরও দ্রুত।
জন লক

53

ইতিমধ্যে অনেক উত্তর রয়েছে যা আপনাকে কীভাবে একটি অনুলিপি তৈরি করতে হয় তা জানায় তবে কেন আপনার আসল 'অনুলিপি' ব্যর্থ হয়েছে তা তাদের কেউই বলেনি।

পাইথন ভেরিয়েবলগুলিতে মান সংরক্ষণ করে না; এটি বস্তুর সাথে নামগুলিকে আবদ্ধ করে। আপনার আসল অ্যাসাইনমেন্টটি রেফারেন্স করা বস্তুকে নিয়েছে 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)

অনুলিপি করার ক্ষেত্রে কর্নার ক্ষেত্রে আরও তথ্যের জন্য ডকুমেন্টেশন দেখুন ।



34

শুরু থেকে শুরু করা যাক এবং এই প্রশ্নটি অন্বেষণ করা যাক।

সুতরাং ধরা যাক আপনার দুটি তালিকা রয়েছে:

list_1=['01','98']
list_2=[['01','98']]

এবং আমাদের উভয় তালিকার অনুলিপি করতে হবে, এখন প্রথম তালিকা থেকে শুরু করে:

সুতরাং প্রথমে ভেরিয়েবলটি copyআমাদের মূল তালিকায় সেট করে চেষ্টা করি list_1:

copy=list_1

এখন আপনি যদি ভাবছেন যে তালিকাটি অনুলিপি করে অনুলিপি করা হয়, তবে আপনি ভুল। idফাংশন দুটি ভেরিয়েবল একই বস্তুর দিকে নির্দেশ করতে পারেন আমাদেরকে দেখাতে পারবেন না। এর চেষ্টা করুন:

print(id(copy))
print(id(list_1))

আউটপুটটি হ'ল:

4329485320
4329485320

উভয় ভেরিয়েবল হুবহু একই যুক্তি। আপনি বিস্মিত?

সুতরাং আমরা যেমন জানি যে পাইথন কোনও ভেরিয়েবলে কোনও জিনিস সংরক্ষণ করে না, ভেরিয়েবলগুলি কেবলমাত্র বস্তুর এবং বস্তুর স্টোরের মান উল্লেখ করে। এখানে বস্তুটি একটিlist তবে আমরা দুটি একই ভিন্ন ভিন্ন ভেরিয়েবল নাম দ্বারা দুটি রেফারেন্স তৈরি করেছি। এর অর্থ হ'ল উভয় ভেরিয়েবল কেবল একই নামের সাথে একই বস্তুর দিকে নির্দেশ করছে।

আপনি যখন করবেন copy=list_1, এটি আসলে করছে:

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্রের তালিকায়_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']]

এটি কিছুটা বিভ্রান্ত বলে মনে হতে পারে, কারণ আমরা আগে একই পদ্ধতি ব্যবহার করেছি worked আসুন এটি বোঝার চেষ্টা করা যাক।

যখন তুমি কর:

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

আপনি দেখতে পাচ্ছেন, এটি আসল নেস্টেড তালিকাকে পরিবর্তন করে না, এটি কেবল অনুলিপি করা তালিকাটিই পরিবর্তন করেছে।


33

এটি করার জন্য পাইথনের প্রতিমাটি newList = oldList[:]


33

পাইথন 3.6 সময়

পাইথন ৩.6.৮ ব্যবহার করে টাইমিংয়ের ফলাফলগুলি এখানে রয়েছে। মনে রাখবেন এই সময়গুলি একে অপরের সাথে সম্পর্কিত, পরম নয়।

আমি কেবল অগভীর অনুলিপি করতে list.copy()গিয়ে আটকেছি এবং পাইথন 2 তে সম্ভব হয়নি এমন কিছু নতুন পদ্ধতিও যুক্ত করেছি, যেমন (পাইথন 3 স্লাইস সমতুল্য ) এবং দুটি আনসার প্যাকিং তালিকা ( *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

আমরা পাইথন 2 বিজয়ী এখনও দেখতে ভাল দেখতে পাই তবে পাইথন 3 ছাড়াই না list.copy() খুব বেশি , বিশেষত পরবর্তীকালের উচ্চতর পঠনযোগ্যতার কথা বিবেচনা করে।

গা horse় ঘোড়াটি আনপ্যাকিং এবং পুনরায় প্যাকিং পদ্ধতি ( 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))

1
3.8 এ এখনও একটি অনুরূপ গল্পটি নিশ্চিত করতে পারে b=[*a]- এটি করার একটি সুস্পষ্ট উপায়;)।
সুপারশুট

19

অন্যান্য অবদানকারীদের সবাই দিয়েছেন দুর্দান্ত উত্তর , যা আপনার একক মাত্রা (সমতল) তালিকার সাথে কাজ করে তবে এখন পর্যন্ত উল্লিখিত পদ্ধতিগুলির মধ্যে কেবল copy.deepcopy()একটি তালিকা ক্লোন / অনুলিপি করতে কাজ করে এবং listআপনি যখন থাকবেন তখন নেস্টেড বস্তুগুলিকে নির্দেশ না করে বহুমাত্রিক, নেস্টেড তালিকাগুলি (তালিকার তালিকা) দিয়ে কাজ করা। ফেলিক্স ক্লিং তার উত্তরে এটি উল্লেখ করলেও , ইস্যুটির সাথে সামান্য আরও কিছুটা রয়েছে এবং সম্ভবত বিল্ট-ইনগুলি ব্যবহার করে একটি কার্যকর সমাধান রয়েছে যা এর দ্রুত বিকল্প প্রমাণ করতে পারে deepcopy

যদিও new_list = old_list[:] , copy.copy(old_list)'এবং পাই3 কে old_list.copy()একক স্তরযুক্ত তালিকাগুলির জন্য কাজ করে, তারা listএবং old_listও এর মধ্যে অবস্থিত অবজেক্টগুলিকে নির্দেশ করে ফিরে যায় এবং এর new_listএকটিতে পরিবর্তিত হয়list বস্তু অন্য রেখে করা হয়।

সম্পাদনা: নতুন তথ্য প্রকাশিত হয়েছে

যেমন অ্যারন হল এবং প্রাইম 2 রিং উভয় দ্বারা চিহ্নিত করা কেবল ব্যবহার করা খারাপ ধারণা নয়, এটি এর চেয়ে ধীর গতিতেও হয় eval()copy.deepcopy()

এর অর্থ হল যে বহুমাত্রিক তালিকার জন্য, একমাত্র বিকল্প copy.deepcopy()। এটি বলা হচ্ছে, আপনি যখন পরিমিত আকারের বহুমাত্রিক অ্যারে ব্যবহার করার চেষ্টা করেন তখন দক্ষতা দক্ষিণ দিকে চলে যায় বলে এটি আসলেই কোনও বিকল্প নয়। আমি চেষ্টা করেছিtimeit একটি 42x42 অ্যারে ব্যবহার , বায়োইনফরমেটিক্স অ্যাপ্লিকেশনগুলির জন্য শোনেনি বা এমনকি এটি বৃহত্তর নয়, এবং আমি একটি প্রতিক্রিয়ার অপেক্ষায় ছেড়ে দিয়েছিলাম এবং এই পোস্টে আমার সম্পাদনা টাইপ করা শুরু করেছি।

দেখে মনে হয় একমাত্র আসল বিকল্পটি হ'ল একাধিক তালিকাগুলি শুরু করা এবং সেগুলিতে স্বতন্ত্রভাবে কাজ করা। বহুমাত্রিক তালিকার অনুলিপি কীভাবে পরিচালনা করতে হবে তার জন্য কারও কাছে যদি অন্য কোনও পরামর্শ থাকে তবে এটি প্রশংসিত হবে।

অন্যরা যেমন বলেছে, মডিউলটি ব্যবহার করে এবং বহুমাত্রিক তালিকার জন্য উল্লেখযোগ্য পারফরম্যান্সের সমস্যা রয়েছে ।copycopy.deepcopy


5
এটি সর্বদা কার্যকর হবে না, যেহেতু কোনও গ্যারান্টি নেই যে ফেরত আসা স্ট্রিংটি repr()বস্তুটিকে পুনরায় তৈরি করতে যথেষ্ট। এছাড়াও, eval()সর্বশেষ অবলম্বনের একটি সরঞ্জাম; দেখুন এভাল সত্যই ভিজিটর নেড ব্যাচেল্ডারের কাছে তথ্যের জন্য বিপজ্জনক । সুতরাং আপনি যখন ব্যবহারের পক্ষে কথা বলছেন তখন eval()আপনার সত্যই উল্লেখ করা উচিত যে এটি বিপজ্জনক হতে পারে।
প্রধানমন্ত্রী 2Ring

1
ন্যায্য বিন্দু. যদিও আমি মনে করি ব্যাচেল্ডারের বক্তব্যটি হ'ল eval()সাধারণভাবে পাইথনে ফাংশনটি হ'ল ঝুঁকিপূর্ণ। আপনি কোডটিতে ফাংশনটি ব্যবহার করেন বা না করেন তা এতটা নয় তবে এটি পাইথনের এবং নিজেই একটি সুরক্ষা গর্ত। আমার উদাহরণস্বরূপ এটা ব্যবহার করছে না একটি ফাংশন যে থেকে ইনপুট পায় সঙ্গে input(), sys.agrvঅথবা এমনকি একটি টেক্সট ফাইল। এটি আরও একবার ফাঁকা বহুমাত্রিক তালিকা শুরু করার পংক্তির পাশাপাশি আরও একবার এটি লুপের প্রতিটি পুনরাবৃত্তিতে পুনরায় পুনর্নির্মাণের পরিবর্তে একটি লুপে অনুলিপি করার উপায় রয়েছে।
এএমআর

1
@ অ্যারোনহাল যেমন উল্লেখ করেছেন, সম্ভবত ব্যবহারের ক্ষেত্রে উল্লেখযোগ্য পারফরম্যান্সের সমস্যা রয়েছে new_list = eval(repr(old_list)), সুতরাং এটি একটি খারাপ ধারণা হওয়া ছাড়াও সম্ভবত এটি কাজ করার ক্ষেত্রেও খুব ধীর।
এএমআর

12

এটি আমাকে অবাক করে দিয়েছিল যে এটি এখনও উল্লেখ করা হয়নি, তাই সম্পূর্ণতার জন্য ...

আপনি "স্প্ল্যাট অপারেটর" দিয়ে তালিকাটি আনপ্যাকিং সম্পাদন করতে পারেন: *এটি আপনার তালিকার উপাদানগুলিও অনুলিপি করবে।

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+ তে উপলব্ধ in

সময়সাপেক্ষে যদিও এটি অন্যান্য সাধারণ পদ্ধতির চেয়ে ভাল পারফর্ম করে।

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)

1
অনুলিপিগুলি সংশোধন করার সময় এই পদ্ধতিটি কীভাবে আচরণ করে?
not2qubit

2
@ not2qubit এর অর্থ কী আপনি নতুন তালিকার উপাদানগুলিতে সংযোজন বা সম্পাদনা করতে পারেন। উদাহরণস্বরূপ old_listএবং new_listদুটি পৃথক তালিকাগুলি হ'ল একটি সম্পাদনা করলে অন্যটি পরিবর্তন হবে না (যদি না আপনি সরাসরি উপাদানগুলিকে নিজেরাই পরিবর্তন করতে পারেন (যেমন তালিকার তালিকা হিসাবে), এই পদ্ধতির কোনওটিই অনুলিপি নয়)।
এসসিবি

7

পাইথন সংস্করণে স্বতন্ত্র একটি খুব সহজ পদ্ধতির ইতিমধ্যে প্রদত্ত উত্তরে অনুপস্থিত ছিল যা আপনি বেশিরভাগ সময় (কমপক্ষে আমি করতে পারি) ব্যবহার করতে পারেন:

new_list = my_list * 1       #Solution 1 when you are not using nested lists

তবে, মাই_লিস্টে যদি অন্য ধারক থাকে (যেমন: নেস্টেড তালিকাগুলি) আপনার অবশ্যই অনুলিপি লাইব্রেরি থেকে উপরের উত্তরের পরামর্শ অনুসারে ডিপকপি ব্যবহার করতে হবে। উদাহরণ স্বরূপ:

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

7

মনে রাখবেন যে কয়েকটি ক্ষেত্রে আপনার নিজস্ব কাস্টম শ্রেণীর সংজ্ঞা দেওয়া হয়েছে এবং আপনি যদি বৈশিষ্ট্যগুলি রাখতে চান তবে বিকল্পগুলি ব্যবহার করার পরিবর্তে আপনার ব্যবহার করা উচিত 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

4
new_list = my_list[:]

new_list = my_list এটি বুঝতে চেষ্টা করুন। ধরা যাক যে মাই_লিস্টটি এক্স এক্সের অবস্থানের হিপ মেমরিতে রয়েছে অর্থাৎ আমার_লিস্টটি এক্সকে নির্দেশ করছে Nownew_list = my_list আপনাকে তালিকাটি এক্সকে নির্দেশ করছে This এটি অগভীর অনুলিপি হিসাবে পরিচিত।

এখন আপনি যদি নিয়োগ new_list = my_list[:] আপনি কেবল আমার_লিস্টের প্রতিটি বস্তুকে নতুন তালিকাতে অনুলিপি করছেন। এটি ডিপ কপি হিসাবে পরিচিত।

আপনি যে অন্যান্য উপায়ে এটি করতে পারেন তা হ'ল:

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)

2

আমি কিছু আলাদা পোস্ট করতে চেয়েছিলাম তারপরে অন্য কয়েকটি উত্তর। যদিও এটি সম্ভবত সবচেয়ে বোধগম্য বা দ্রুততম বিকল্প নয়, এটি গভীর অনুলিপি কীভাবে কাজ করে তার পাশাপাশি কিছুটা গভীর অনুলিপি করার বিকল্প বিকল্প হিসাবে এটি কিছুটা অভ্যন্তরীণ দৃষ্টিভঙ্গি সরবরাহ করে। আমার ফাংশনটিতে বাগ রয়েছে কিনা তা আসলেই কিছু যায় আসে না, কারণ এটির মূল বিষয়টি প্রশ্নের উত্তরগুলির মতো বিষয়গুলি অনুলিপি করার উপায় দেখানো হয়, তবে ডিপকপিটি এর মূল অংশে কীভাবে কাজ করে তা ব্যাখ্যা করার জন্য এটি ব্যবহার করে।

যে কোনও গভীর অনুলিপি ফাংশনের মূল অংশটি হল অগভীর অনুলিপি তৈরির উপায়। কিভাবে? সহজ। যে কোনও গভীর অনুলিপি ফাংশন কেবলমাত্র অপরিবর্তনীয় বস্তুর পাত্রে অনুলিপি করে। আপনি যখন কোনও নেস্টেড তালিকাকে গভীরভাবে অনুলিপি করেন, আপনি কেবলমাত্র বাইরের তালিকাগুলির নকল করে থাকেন, তালিকার অভ্যন্তরে পরিবর্তনযোগ্য বস্তুগুলি নয়। আপনি কেবল পাত্রে নকল করছেন। ক্লাসের জন্যও একই কাজ করে। আপনি যখন কোনও শ্রেণীর ডিপকপি করেন, আপনি তার সমস্ত পরিবর্তনীয় বৈশিষ্ট্যগুলি ডিপকপি করেন। তা কিভাবে? কীভাবে আপনার কেবল পাত্রে অনুলিপি করতে হবে, যেমন তালিকাগুলি, ডিক্টস, টিপলস, ইটারস, ক্লাস এবং শ্রেণীর উদাহরণগুলি?

ইহা সাধারণ. একটি পরিবর্তনীয় বস্তুর সত্যই সদৃশ করা যায় না। এটি কখনই পরিবর্তন করা যায় না, সুতরাং এটি কেবলমাত্র একক মান। তার মানে আপনার কখনই স্ট্রিং, সংখ্যা, বুল বা এর কোনও একটির নকল করতে হবে না। তবে আপনি কীভাবে পাত্রে নকল করবেন? সহজ। আপনি সমস্ত মান সহ সবেমাত্র একটি নতুন ধারক সূচনা করতে পারেন। ডিপকপি পুনরাবৃত্তি উপর নির্ভর করে। এটি সমস্ত পাত্রে এমনকি কোনও পাত্রে রেখে দেওয়া অবধি কন্টেনার সহ এমন কন্টেনারগুলিও নকল করে। একটি ধারক একটি অপরিবর্তনীয় বস্তু।

একবার আপনি যখন জানলেন, কোনও রেফারেন্স ছাড়াই কোনও অবজেক্টকে সম্পূর্ণ নকল করা বেশ সহজ। বেসিক ডেটা-টাইপগুলি গভীরভাবে কপি করার জন্য এখানে একটি ফাংশন রয়েছে (কাস্টম ক্লাসগুলির জন্য কাজ করবে না তবে আপনি সর্বদা এটি যুক্ত করতে পারেন)

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] । অপরিবর্তনীয় সংখ্যাগুলি নকল করা যায় না, তবে অন্য স্তরটি পারে। আপনি একটি তালিকা বোধগম্যতা ব্যবহার করে এটির সদৃশ করতে পারেন: [x এর জন্য x [1, 2, 3]

এখন, আপনার এই তালিকাটি কল্পনা করুন: [[1, 2], [3, 4], [5, 6]] । এবার আপনি একটি ফাংশন করতে চান যা তালিকার সমস্ত স্তর গভীরভাবে অনুলিপি করতে পুনরাবৃত্তি ব্যবহার করে। পূর্ববর্তী তালিকা বোঝার পরিবর্তে:

[x for x in _list]

এটি তালিকার জন্য একটি নতুন ব্যবহার করে:

[deepcopy_list(x) for x in _list]

এবং ডিপকপি_লিস্টটি এর মতো দেখাচ্ছে:

def deepcopy_list(x):
  if isinstance(x, (str, bool, float, int)):
    return x
  else:
    return [deepcopy_list(y) for y in x]

তারপরে এখন আপনার একটি ফাংশন রয়েছে যা পুনরাবৃত্তি ব্যবহার করে অসীম বহু স্তরকে তালিকাভুক্ত স্টারস, বুলস, ফ্লস্ট, ইনটস এমনকি এমনকি তালিকার কোনও তালিকা ডিপকপি করতে পারে। এবং সেখানে আপনার এটি আছে, গভীর কপি করা।

টিএলডিআর : ডিপকপি অনুলিপিযুক্ত বস্তুগুলির পুনরাবৃত্তি ব্যবহার করে এবং কেবল পূর্বের মতো একই অপরিবর্তনীয় বস্তুগুলি ফিরিয়ে দেয়, কারণ অপরিবর্তনীয় বস্তুগুলি নকল করা যায় না। যাইহোক, এটি পরিবর্তনীয় অবজেক্টগুলির সর্বাধিক অভ্যন্তরীণ স্তরগুলি গভীরভাবে প্রতিবিম্বিত করে যতক্ষণ না এটি কোনও অবজেক্টের বহিরাগততম পরিবর্তনীয় স্তরে পৌঁছায়।


2

আইডি এবং গিসির মাধ্যমে স্মৃতি সন্ধান করার জন্য একটি সামান্য ব্যবহারিক দৃষ্টিভঙ্গি।

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

2

মনে রাখবেন পাইথনে আপনি যখন করবেন:

    list1 = ['apples','bananas','pineapples']
    list2 = list1

তালিকা 2 প্রকৃত তালিকা সংরক্ষণ করছে না, তবে তালিকা 1-এর একটি রেফারেন্স। সুতরাং আপনি যখন তালিকা 1 তে কিছু করেন তখন তালিকা 2 পরিবর্তন হয়। তালিকার মূল কপি তৈরি করতে অনুলিপি মডিউলটি (ডিফল্ট নয়, পিপে ডাউনলোড করুন) ব্যবহার করুন ( copy.copy()সাধারণ তালিকার copy.deepcopy()জন্য, নেস্টেডদের জন্য)। এটি এমন একটি অনুলিপি তৈরি করে যা প্রথম তালিকার সাথে পরিবর্তন হয় না।


0

ডিপকপি বিকল্পটি হ'ল একমাত্র পদ্ধতি যা আমার পক্ষে কাজ করে:

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]]]
-----------------------------
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.