ලැයිස්තුවක් ක්ලෝන කරන්නේ හෝ පිටපත් කරන්නේ කෙසේද?


2567

පයිතන් හි ලැයිස්තුවක් ක්ලෝන කිරීමට හෝ පිටපත් කිරීමට ඇති විකල්ප මොනවාද?

භාවිතා කරන අතරතුර new_list = my_list, ඕනෑම වෙනස් new_listවෙනස් my_listදේවල්. ඇයි මේ?

Answers:


3353

සමඟ 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))

ප්‍රති ult ලය:

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 හි ද හැකියාවක් ඇත newlist = list(mylist).
ස්ටෙෆාන්

9
තවත් හැකියාවක් වන්නේ new_list = old_list * 1
aris

4
මෙම ක්‍රම අතුරින් නොගැඹුරු පිටපතක් සහ ගැඹුරු පිටපත් මොනවාද?
ඊස්වර්

4
S එස්වර්: අන්තිම එක හැර අන් සියල්ලම නොගැඹුරු පිටපතක් කරයි
ෆීලික්ස් ක්ලින්ග්

3
S ඊස්වර් එය නොගැඹුරු පිටපතකි.
juanpa.arrivillaga

607

ෆීලික්ස් දැනටමත් විශිෂ්ට පිළිතුරක් ලබා දී ඇත, නමුත් විවිධ ක්‍රම සමඟ සැසඳීමක් කිරීමට මම සිතුවෙමි:

  1. තත්පර 10.59 (105.9us / itn) - copy.deepcopy(old_list)
  2. තත්පර 10.16 (101.6us / itn) - Copy()ගැඹුරු පිටපතක් සමඟ පන්ති පිටපත් කරන පිරිසිදු පයිතන් ක්‍රමය
  3. තත්පර 1.488 (14.88us / itn) - පිරිසිදු පයිතන් Copy()ක්‍රමය පන්ති පිටපත් නොකිරීම (නියෝග / ලැයිස්තු / ටුපල් පමණි)
  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[:]( ලැයිස්තු කැපීම )

එබැවින් වේගවත්ම වන්නේ ලැයිස්තු කැපීමයි. එහෙත් බව දැනුවත් විය 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 භාවිතා කරමින් මෙම සංඛ්‍යා 2017 දී තවමත් නිවැරදිද? මම පහත පිළිතුර සඳහන් කරමි ( stackoverflow.com/a/17810305/26219 ) දැනටමත් මෙම පිළිතුර ප්‍රශ්න කරයි.
මාර්ක් එඩින්ටන්

4
timeitමොඩියුලය භාවිතා කරන්න . මේ වගේ අත්තනෝමතික ක්ෂුද්‍ර මිණුම් සලකුණු වලින් ඔබට බොහෝ දේ නිගමනය කළ නොහැකිය.
කොරී ගෝල්ඩ්බර්ග්

3
3.5+ සඳහා නව විකල්පයක් ඇතුළත් කිරීමට ඔබ කැමති නම්, [*old_list]දළ වශයෙන් සමාන විය යුතුය list(old_list), නමුත් එය සාමාන්‍ය ක්‍රියාකාරී ඇමතුම් මාර්ග නොව සින්ටැක්ස් බැවින්, එය ධාවන වේලාවෙන් ටිකක් ඉතිරි කරයි (සහ මෙන් නොව old_list[:], පරිවර්තනයක් ටයිප් නොකරන, [*old_list]ඕනෑම ක්‍රියාකාරීත්වයකින් ක්‍රියා කරන අතර නිෂ්පාදනය කරයි a list).
ෂැඩෝ රේන්ජර්

3
Ore කෝරිගෝල්ඩ්බර්ග් තරමක් අඩු අත්තනෝමතික ක්ෂුද්‍ර මිණුම් ලකුණක් සඳහා (භාවිතා කරයි timeit, 100k වෙනුවට මීටර් 50 ක් ධාවනය වේ) stackoverflow.com/a/43220129/3745896
ගංගාව

1
Ha ෂැඩෝ රේන්ජර් [*old_list]ඇත්ත වශයෙන්ම වෙනත් ඕනෑම ක්‍රමයක් අභිබවා යයි. (පෙර අදහස් දැක්වීම්වල මගේ පිළිතුර බලන්න)
ගංගා

152

පයිතන් 3.3+ ක්‍රමය එකතු කරන බව මට පවසා ඇති අතර එය පෙති කැපීම තරම් වේගවත් විය යුතුය:list.copy()

newlist = old_list.copy()


6
ඔව්, සහ docs docs.python.org/3/library/stdtypes.html#mutable-afterence-types අනුව , s.copy()නොගැඹුරු පිටපතක් s(සමාන s[:]) නිර්මාණය කරයි .
CyberMew

1
ඇත්තටම එය දැනට, බව පෙනේ python3.8, .copy()වන තරමක් වේගයෙන් යසිකා වඩා. AaAronsHall පිළිතුර පහත බලන්න.
love.by.Jesus

126

පයිතන් හි ලැයිස්තුවක් ක්ලෝන කිරීමට හෝ පිටපත් කිරීමට ඇති විකල්ප මොනවාද?

පයිතන් 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

පයිතන් 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'], [], []]

ලැයිස්තුව හුදෙක් අන්තර්ගතයට යොමුකරන්නන් සමූහයකි, එබැවින් නොගැඹුරු පිටපතක් මඟින් දර්ශකයන් පිටපත් කරයි, එබැවින් ඔබට වෙනස් ලැයිස්තු දෙකක් ඇත, නමුත් ඒවාට එකම අන්තර්ගතයන් ඇත. අන්තර්ගතයේ පිටපත් සෑදීම සඳහා ඔබට ගැඹුරු පිටපතක් අවශ්‍ය වේ.

ගැඹුරු පිටපත්

ලැයිස්තුවක ගැඹුරු පිටපතක්deepcopycopy සෑදීමට , පයිතන් 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))
  1. එය භයානක ය, විශේෂයෙන් ඔබ විශ්වාස නොකරන ප්‍රභවයකින් යමක් තක්සේරු කරන්නේ නම්.
  2. එය විශ්වාසදායක නොවේ, ඔබ පිටපත් කරන උප කොටසකට සමාන මූලද්‍රව්‍යයක් ප්‍රතිනිෂ්පාදනය කිරීම සඳහා නිරූපණය කළ හැකි නිරූපණයක් නොමැති නම්.
  3. එය ද අඩු කාර්ය සාධනයකි.

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

1
ලැයිස්තුව 2D නම් ඔබට ගැඹුරු පිටපතක් අවශ්‍ය නොවේ. එය ලැයිස්තු ලැයිස්තුවක් නම්, එම ලැයිස්තු තුළ ඒවායේ ලැයිස්තු නොමැති නම්, ඔබට ලූපයක් භාවිතා කළ හැකිය. දැනට, මම භාවිතා කරන list_copy=[] for item in list: list_copy.append(copy(item))අතර එය වඩා වේගවත් ය.
ජෝන් ලොක්

54

නිසි පිටපතක් සාදා ගන්නේ කෙසේදැයි ඔබට දැනටමත් පිළිතුරු බොහොමයක් ඇත, නමුත් ඔබේ මුල් පිටපත අසමත් වූයේ මන්දැයි ඔවුන්ගෙන් කිසිවෙක් නොකියයි.

පයිතන් විචල්‍යයන්හි අගයන් ගබඩා නොකරයි; එය වස්තු සමඟ නම් බැඳ තබයි. ඔබේ මුල් පැවරුම මඟින් යොමු කරන ලද වස්තුව ගෙන එය 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)

පිටපත් කිරීමේදී ඇති වන අවස්ථා පිළිබඳ වැඩි විස්තර සඳහා ප්‍රලේඛනය බලන්න .



36

අපි මුල සිටම ආරම්භ කර මෙම ප්‍රශ්නය ගවේෂණය කරමු.

එබැවින් ඔබට ලැයිස්තු දෙකක් ඇතැයි සිතමු:

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

අපි ලැයිස්තු දෙකම පිටපත් කළ යුතුයි, දැන් පළමු ලැයිස්තුවෙන් ආරම්භ වේ:

එබැවින් පළමුව විචල්‍යය copyඅපගේ මුල් ලැයිස්තුවට සැකසීමෙන් උත්සාහ කරමු list_1:

copy=list_1

දැන් ඔබ සිතන්නේ නම් පිටපත ලැයිස්තුව_1 පිටපත් කළා නම් ඔබ වැරදියි. මෙම idවිචල්යයන් දෙකක් එකම වස්තුව යොමුකල හැකි නම් කාර්යය අපට පෙන්වන්න පුළුවන්. අපි මෙය උත්සාහ කරමු:

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

ප්‍රතිදානය:

4329485320
4329485320

විචල්යයන් දෙකම එකම තර්කයයි. ඔබ පුදුම වෙනවාද?

පයිතන් විචල්‍යයක කිසිවක් ගබඩා නොකරන බව අප දන්නා පරිදි, විචල්‍යයන් යනු වස්තුව හා වස්තුව ගබඩා කිරීම සඳහා වන අගය පමණි. මෙන්න වස්තුව a 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']]

මෙය ටිකක් ව්‍යාකූල බවක් පෙනෙන්නට තිබේ, මන්ද අප කලින් භාවිතා කළ ක්‍රමයම ක්‍රියාත්මක වූ බැවිනි. මෙය තේරුම් ගැනීමට උත්සාහ කරමු.

ඔබ කරන විට:

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

ඔබට පෙනෙන පරිදි, එය මුල් කැදැලි ලැයිස්තුව වෙනස් කළේ නැත, එය වෙනස් කළේ පිටපත් කළ ලැයිස්තුව පමණි.


34

මෙය සිදු කිරීම සඳහා පයිතන්ගේ මෝඩකම වේ newList = oldList[:]


34

පයිතන් 3.6 වේලාව

Python 3.6.8 භාවිතා කරමින් කාල ප්‍රති results ල මෙන්න. මෙම කාලය එකිනෙකාට සාපේක්ෂ වන බව මතක තබා ගන්න, නිරපේක්ෂ නොවේ.

මම නොගැඹුරු පිටපත් පමණක් කිරීමට පෙළඹී ඇති අතර, list.copy()(පයිතන් 3 පෙත්තට සමාන ) සහ ලැයිස්තු ඉවත් කිරීම ( *new_list, = listසහ new_list = [*list]) ආකාර දෙකක් වැනි පයිතන් 2 හි කළ නොහැකි නව ක්‍රම කිහිපයක්ද එක් කළෙමි .

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()බොහෝ දුරට එලියට එන්නේ නැත .

අඳුරු අශ්වයා යනු ඉවත් කිරීම සහ නැවත ඇසුරුම් කිරීමේ ක්‍රමයයි (b = [*a] ) වන අතර එය අමු පෙති කැපීමට වඩා ~ 25% වේගවත් වන අතර අනෙක් ඉවත් කිරීමේ ක්‍රමයට වඩා දෙගුණයකටත් වඩා වේගවත් *b, = aවේ.

b = a * 1 පුදුම හිතෙන තරම් හොඳයි.

මෙම ක්‍රම මඟින් ලැයිස්තු හැර වෙනත් ආදානයකට සමාන ප්‍රති results ල නොලැබෙන බව සලකන්න . ඒවා සියල්ලම පෙති කපන වස්තූන් සඳහා වැඩ කරයි, ස්වල්පයක් ඕනෑම නැවත කළ හැකි දේ සඳහා වැඩ කරයි, නමුත් පමණි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]- එය කළ හැකි එකම ක්‍රමය;).
සුපර්ෂූට්

20

අනෙක් සියලුම දායකයින් විශාල පිළිතුරු ලබා දුන් අතර, ඔබට තනි මානයන් (සමතලා) ලැයිස්තුවක් ඇති විට එය ක්‍රියාත්මක වේ, කෙසේ වෙතත් මෙතෙක් සඳහන් කර ඇති ක්‍රම කෙසේ වෙතත්, copy.deepcopy()ක්‍රියා කරන්නේ ලැයිස්තුවක් ක්ලෝන කිරීමට / පිටපත් කිරීමට පමණක් වන listඅතර ඔබ සිටින විට එය කැදැලි වස්තූන් වෙත යොමු නොකරයි. බහුවිධ, කැදැලි ලැයිස්තු සමඟ වැඩ කිරීම (ලැයිස්තු ලැයිස්තුව). ෆීලික්ස් ක්ලින්ග් සිය පිළිතුරෙහි එය සඳහන් කළද , ගැටලුවට තව ටිකක් වැඩි යමක් ඇති අතර, ඊට වඩා වේගවත් විකල්පයක් සනාථ කළ හැකි බිල්ට්-ඉන් භාවිතා කරමින් ක්‍රියාමාර්ගයක් ගත හැකිය deepcopy.

අතර new_list = old_list[:], copy.copy(old_list)'සහ Py3k සඳහා old_list.copy()වැඩ තනි-එල්ල ලැයිස්තු සඳහා, ඔවුන් ට යොමු ප්රතිවර්තනය listතුළ පතරෙහි වස්තූන් old_listහා new_listඑම එක් කිරීමට, සහ වෙනස්list වස්තූන් අනෙක් දී පවත්වා ගැනීම වේ.

සංස්කරණය කරන්න: නව තොරතුරු හෙළිදරව් වේ

ලෙස දෙකම විසින් පෙන්වා දෙන ලදී ආරොන් ශාලාව සහ අගමැති 2Ring භාවිතා eval()නරක අදහසක් පමණක් නොවේ, එය ද බෙහෙවින් අඩු වඩා copy.deepcopy().

මෙයින් අදහස් කරන්නේ බහුවිධ ලැයිස්තු සඳහා එකම විකල්පය copy.deepcopy()බවයි. එසේ පැවසීමත් සමඟම, එය මධ්‍යස්ථ විකල්ප ප්‍රමාණයේ බහුමානීය අරාවකින් භාවිතා කිරීමට උත්සාහ කරන විට කාර්ය සාධනය දකුණට යන බැවින් එය ඇත්තෙන්ම විකල්පයක් නොවේ. මම උත්සාහ කලාtimeit 42x42 අරා භාවිතා කළෙමි, එය ජෛව තොරතුරු යෙදුම් සඳහා අසා නැති හෝ එතරම් විශාල නොවූ අතර, ප්‍රතිචාරයක් බලාපොරොත්තුවෙන් සිටීම මම අත්හැර දමා මෙම සංස්කරණයට මගේ සංස්කරණය ටයිප් කිරීමට පටන් ගතිමි.

එවිට ඇති එකම සැබෑ විකල්පය නම් බහුවිධ ලැයිස්තු ආරම්භ කර ඒවා ස්වාධීනව වැඩ කිරීමයි. යමෙකුට වෙනත් යෝජනා තිබේ නම්, බහුවිධ ලැයිස්තු පිටපත් කිරීම හැසිරවිය යුතු ආකාරය සඳහා එය අගය කරනු ඇත.

අනෙක් අය ප්‍රකාශ කර ඇති පරිදි, මොඩියුලය භාවිතා කරමින් සහ බහුමාන ලැයිස්තු සඳහා සැලකිය යුතු කාර්යසාධන ගැටළු තිබේ.copycopy.deepcopy


5
repr()වස්තුව නැවත නිර්මාණය කිරීම සඳහා ආපසු ලබා දුන් නූල ප්‍රමාණවත් බවට සහතිකයක් නොමැති බැවින් මෙය සැමවිටම ක්‍රියාත්මක නොවේ . එසේම, eval()අවසාන උපක්‍රමයේ මෙවලමකි; බලන්න Eval ඇත්තටම භයානකයි විස්තර සඳහා SO ප්රවීණ නෙඩ් Batchelder විසින්. ඔබ භාවිතා ඉල්ලා සිටිති විට ඒ නිසා eval()ඔබ ඇත්තටම එය අනතුරුදායක විය හැකි බව සඳහන් කර තිබිය යුතුය.
PM 2Ring

1
සාධාරණ කරුණ. මම හිතන්නේ බැට්චෙල්ඩර්ගේ අදහස නම් eval()පොදුවේ පයිතන්හි ක්‍රියාකාරිත්වය තිබීම අවදානමක් බවයි. ඔබ කේතයේ ශ්‍රිතය භාවිතා කළත් නැතත් එය එතරම් නොවේ, නමුත් එය පයිතන්හි සහ තමා තුළම ඇති ආරක්ෂක කුහරයකි. මගේ උදාහරණය ආදාන ලැබෙන බව ක්රියාකාරිත්වයට, එය භාවිතා නොවේ input(), sys.agrvහෝ වෙනත් පෙළ ගොනුවකට පවා. එය එක් වරක් හිස් බහුවිධ ලැයිස්තුවක් ආරම්භ කිරීමේ රේඛා ඔස්සේ වැඩි වන අතර, පසුව ලූපයේ එක් එක් පුනරාවර්තනයේදී නැවත ආරම්භ කිරීම වෙනුවට එය ලූපයක පිටපත් කිරීමේ ක්‍රමයක් ඇත.
AMR

1
A ආරොන්හෝල් පෙන්වා දී ඇති පරිදි, භාවිතා කිරීම සඳහා සැලකිය යුතු කාර්යසාධන ගැටළුවක් ඇති විය හැකි new_list = eval(repr(old_list))බැවින් එය නරක අදහසක් වීමට අමතරව, එය වැඩ කිරීමට ප්‍රමාද වැඩිය.
AMR

13

මෙය පුදුමයට කරුණක් වන්නේ මෙය තවම සඳහන් නොවීමයි, එබැවින් සම්පූර්ණත්වය උදෙසා ...

ඔබට "ස්ප්ලැට් ක්‍රියාකරු" සමඟ ලැයිස්තු ඉවත් කිරීම සිදු කළ හැකිය:, *එය ඔබගේ ලැයිස්තුවේ අංග පිටපත් කරනු ඇත.

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)

1
පිටපත් වෙනස් කිරීමේදී මෙම ක්‍රමය ක්‍රියා කරන්නේ කෙසේද?
not2qubit

2
2 not2qubit ඔබ අදහස් කරන්නේ නව ලැයිස්තුවේ අංග එකතු කිරීම හෝ සංස්කරණය කිරීමයි. උදාහරණයේ දී old_listසහ new_listවෙනස් ලැයිස්තු දෙකක් වන අතර, එකක් සංස්කරණය කිරීමෙන් අනෙක වෙනස් නොවේ (ඔබ මූලද්‍රව්‍යයන් කෙලින්ම විකෘති නොකරන්නේ නම් (ලැයිස්තු ලැයිස්තුව වැනි), මෙම ක්‍රම කිසිවක් ගැඹුරු පිටපත් නොවේ).
SCB

8

ඔබට බොහෝ විට භාවිතා කළ හැකි දැනටමත් ලබා දී ඇති පිළිතුරු වල පයිතන් අනුවාදයෙන් ස්වාධීන ඉතා සරල ප්‍රවේශයක් අස්ථානගත වී ඇත (අවම වශයෙන් මම එසේ කරමි):

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

8

ඔබ ඔබේ අභිරුචි පංතිය නිර්වචනය කර ඇති අතර ඔබට ගුණාංග තබා ගැනීමට අවශ්‍ය නම් විකල්ප භාවිතා කිරීමට 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

5
new_list = my_list[:]

new_list = my_list මෙය තේරුම් ගැනීමට උත්සාහ කරන්න. X_ ස්ථානයේ my_list ගොඩවල් මතකයේ ඇති බව කියමු. දැන් my_list X වෙත යොමු වේ. දැන් new_list = my_listඔබට පැවරීමෙන් නව_ ලැයිස්තුව X වෙත යොමු කිරීමට ඉඩ දෙන්න. මෙය නොගැඹුරු පිටපතක් ලෙස හැඳින්වේ.

දැන් ඔබ new_list = my_list[:]පැවරුවහොත් ඔබ මගේ_ ලැයිස්තුවේ සෑම වස්තුවක්ම නව_ ලැයිස්තුවට පිටපත් කරයි. මෙය ගැඹුරු පිටපතක් ලෙස හැඳින්වේ.

ඔබට මෙය කළ හැකි අනෙක් ක්‍රමය නම්:

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

3

මට අවශ්‍ය වූයේ ටිකක් වෙනස් දෙයක් පසුව වෙනත් පිළිතුරු කිහිපයක් පළ කිරීමට ය. මෙය බොහෝ දුරට තේරුම්ගත හැකි හෝ වේගවත්ම විකල්පය නොවුනත්, එය ගැඹුරු පිටපත් ක්‍රියා කරන ආකාරය පිළිබඳ අභ්‍යන්තර දැක්මක් මෙන්ම ගැඹුරු පිටපත් කිරීම සඳහා තවත් විකල්ප විකල්පයක් ද සපයයි. මගේ ශ්‍රිතයට දෝෂ තිබේ නම් එය ඇත්ත වශයෙන්ම වැදගත් නොවේ, මන්දයත් මේ කාරණය වන්නේ ප්‍රශ්න පිළිතුරු වැනි වස්තූන් පිටපත් කිරීමට ක්‍රමයක් පෙන්වීම පමණක් නොව, ගැඹුරු කේන්ද්‍රය එහි හරයේ ක්‍රියා කරන ආකාරය පැහැදිලි කිරීමට මෙය භාවිතා කිරීමයි.

ඕනෑම ගැඹුරු පිටපත් ශ්‍රිතයක හරය නොගැඹුරු පිටපතක් සෑදීමේ ක්‍රමයකි. කෙසේද? සරල. ඕනෑම ගැඹුරු පිටපත් ශ්‍රිතයක් අනුකරණය කරන්නේ වෙනස් කළ නොහැකි වස්තූන්ගේ බහාලුම් පමණි. ඔබ කැදැලි ලැයිස්තුවක් ගැඹුරින් පිටපත් කරන විට, ඔබ කරන්නේ පිටත ලැයිස්තු අනුපිටපත් කිරීම මිස ලැයිස්තු තුළ ඇති විකෘති වස්තු නොවේ. ඔබ කරන්නේ බහාලුම් අනුපිටපත් කිරීම පමණි. පංති සඳහා ද එයම ක්‍රියාත්මක වේ. ඔබ පංතියක් ගැඹුරින් පිටපත් කරන විට, ඔබ එහි විකෘති ගුණාංග සියල්ලම ගැඹුරින් පිටපත් කරයි. ඉතින් කොහොමද? ලැයිස්තු, ඩික්ට්ස්, ටුපල්, අයිටර්ස්, පංති සහ පන්ති අවස්ථා වැනි බහාලුම් පමණක් පිටපත් කිරීමට ඔබට සිදුවන්නේ කෙසේද?

ඒක සරලයි. විකෘති වස්තුවක් අනුපිටපත් කළ නොහැක. එය කිසි විටෙකත් වෙනස් කළ නොහැක, එබැවින් එය තනි අගයක් පමණි. ඒ කියන්නේ ඔබට කිසි විටෙකත් නූල්, අංක, බූල්ස් හෝ ඒ කිසිවක් අනුපිටපත් කිරීමට අවශ්‍ය නැත. නමුත් ඔබ බහාලුම් අනුපිටපත් කරන්නේ කෙසේද? සරල. ඔබ සියලු අගයන් සහිත නව බහාලුමක් ආරම්භ කරන්න. ඩීප්කොපි පුනරාවර්තනය මත රඳා පවතී. බහාලුම් කිසිවක් ඉතිරි නොවන තෙක් එය සියළුම බහාලුම්, ඒවායේ ඇතුළත බහාලුම් පවා අනුපිටපත් කරයි. බහාලුමක් යනු වෙනස් කළ නොහැකි වස්තුවකි.

ඔබ එය දැනගත් පසු, කිසිදු සඳහනක් නොමැතිව වස්තුවක් සම්පූර්ණයෙන්ම අනුපිටපත් කිරීම පහසුය. මූලික දත්ත වර්ග ගැඹුරින් පිටපත් කිරීම සඳහා ශ්‍රිතයක් මෙන්න (අභිරුචි පන්ති සඳහා ක්‍රියා නොකරනු ඇත, නමුත් ඔබට එය සැමවිටම එකතු කළ හැකිය)

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]

හා deepcopy_list මේ වගේ පෙනුම:

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

දැන් ඔබට ශ්‍රිතයක් ඇත, එමඟින් ඕනෑම ස්ටර්ස්, බූල්ස්, ෆ්ලෝස්ට්, ඉන්ට්ස් සහ ලැයිස්තු පවා පුනරාවර්තනය භාවිතා කරමින් අසීමිත ලෙස බොහෝ ස්ථර වලට ලැයිස්තු ගත කළ හැකිය. එහි ඔබ සතුව ඇත, ගැඹුරු පිටපත් කිරීම.

ටීඑල්ඩීආර් : ඩීප්කොපි මඟින් වස්තූන් අනුපිටපත් කිරීම සඳහා පුනරාවර්තනය භාවිතා කරන අතර, වෙනස් කළ නොහැකි වස්තූන් අනුපිටපත් කළ නොහැකි බැවින් පෙර මෙන් වෙනස් කළ නොහැකි වස්තූන් ආපසු ලබා දේ. කෙසේ වෙතත්, එය වස්තුවක පිටත විකෘති ස්ථරයට ළඟා වන තෙක් විකෘති වස්තූන්ගේ අභ්‍යන්තර ස්ථර ගැඹුරින් පිටපත් කරයි.


3

Id සහ gc හරහා මතකය සොයා බැලීමට සුළු ප්‍රායෝගික ඉදිරිදර්ශනයක්.

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

3

ඔබ එසේ කරන විට පයිතන්හි ඇති බව මතක තබා ගන්න:

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

List2 සත්‍ය ලැයිස්තුව ගබඩා නොකරයි, නමුත් list1 වෙත යොමු කිරීමකි. එබැවින් ඔබ ලැයිස්තු 1 සඳහා ඕනෑම දෙයක් කළ විට, ලැයිස්තු 2 ද වෙනස් වේ. ලැයිස්තුවේ මුල් පිටපතක් සෑදීම සඳහා පිටපත් මොඩියුලය භාවිතා කරන්න (පෙරනිමිය නොවේ, පයිප්පයෙන් බාගන්න) ( copy.copy()සරල ලැයිස්තු copy.deepcopy()සඳහා, කැදැලි සඳහා). මෙය පළමු ලැයිස්තුව සමඟ වෙනස් නොවන පිටපතක් සාදයි.


1

මට වැඩ කරන එකම ක්‍රමය ගැඹුරු කේත විකල්පයයි:

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

1

මෙයට හේතුව, රේඛාව new_list = my_listවිචල්‍යයට නව යොමු කිරීමක් ලබා දෙන my_listඅතර එය පහත දැක්වෙන කේතයට new_list සමාන Cවේ,

int my_list[] = [1,2,3,4];
int *new_list;
new_list = my_list;

නව ලැයිස්තුවක් සෑදීමට ඔබ පිටපත් මොඩියුලය භාවිතා කළ යුතුය

import copy
new_list = copy.deepcopy(my_list)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.