programing

Python에서 개체의 복사본을 만드는 방법

prostudy 2022. 4. 4. 21:21
반응형

Python에서 개체의 복사본을 만드는 방법

나는 사물의 복사본을 만들고 싶다.나는 새로운 물체가 옛 물체의 모든 특성(필드의 값)을 소유하기를 원한다.하지만 나는 독립된 물건을 갖고 싶어.그래서 만약 내가 새로운 개체의 필드 값을 변경한다면, 오래된 개체는 그것에 의해 영향을 받지 않아야 한다.

객체의 완전한 독립 사본을 얻으려면 함수를 사용하십시오.

얕고 깊은 복사에 대한 자세한 내용은 이 질문에 대한 다른 답변과 관련 질문에 대한답변의 멋진 설명을 참조하십시오.

Python에서 개체의 복사본을 만드는 방법

그래서 만약 내가 새로운 개체의 필드 값을 변경한다면, 오래된 개체는 그것에 의해 영향을 받지 않아야 한다.

그럼 변이할 수 있는 물체를 말하는 거지?

Python 3에서 리스트는copy방법(2에서는 슬라이스를 사용하여 복사본을 만드는 경우):

>>> a_list = list('abc')
>>> a_copy_of_a_list = a_list.copy()
>>> a_copy_of_a_list is a_list
False
>>> a_copy_of_a_list == a_list
True

얕은 사본

얕은 복사본은 가장 바깥쪽 용기의 복사본일 뿐이다.

list.copy얕은 사본:

>>> list_of_dict_of_set = [{'foo': set('abc')}]
>>> lodos_copy = list_of_dict_of_set.copy()
>>> lodos_copy[0]['foo'].pop()
'c'
>>> lodos_copy
[{'foo': {'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]

내부 물건의 사본을 얻을 수 없다.그것들은 같은 물체다. 그래서 그것들이 변이되면, 두 용기에 변화가 나타난다.

딥 카피

딥 카피는 각 내부 물체의 반복 복제품이다.

>>> lodos_deep_copy = copy.deepcopy(list_of_dict_of_set)
>>> lodos_deep_copy[0]['foo'].add('c')
>>> lodos_deep_copy
[{'foo': {'c', 'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]

변경사항은 원본에 반영되지 않고 사본에만 반영된다.

불변 객체

불변의 객체는 보통 복사할 필요가 없다.사실, 만약 여러분이 하려고 한다면, 파이톤은 여러분에게 원래의 물체를 줄 것이다:

>>> a_tuple = tuple('abc')
>>> tuple_copy_attempt = a_tuple.copy()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'copy'

튜플은 복사법도 없으니 한 조각으로 해 보자.

>>> tuple_copy_attempt = a_tuple[:]

하지만 우리는 그것이 같은 목적임을 안다.

>>> tuple_copy_attempt is a_tuple
True

문자열의 경우에도 유사함:

>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True

프로즌세츠를 위해서, 비록 프로즌세츠가copy방법:

>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True

불변의 객체를 복사해야 하는 시기

변이 가능한 내부 객체를 복사해야 할 경우 불변 객체를 복사해야 한다.

>>> tuple_of_list = [],
>>> copy_of_tuple_of_list = tuple_of_list[:]
>>> copy_of_tuple_of_list[0].append('a')
>>> copy_of_tuple_of_list
(['a'],)
>>> tuple_of_list
(['a'],)
>>> deepcopy_of_tuple_of_list = copy.deepcopy(tuple_of_list)
>>> deepcopy_of_tuple_of_list[0].append('b')
>>> deepcopy_of_tuple_of_list
(['a', 'b'],)
>>> tuple_of_list
(['a'],)

우리가 알 수 있듯이 사본의 내부 사물이 변이될 때 원본은 변하지 않는다.

사용자 지정 개체

사용자 지정 개체는 일반적으로 데이터를__dict__속성이든 속성이든__slots__(투플과 같은 메모리 구조)

복사 가능한 개체를 만들려면 정의하십시오.__copy__(낮은 복사본의 경우) 및/또는__deepcopy__(심층 사본의 경우).

from copy import copy, deepcopy

class Copyable:
    __slots__ = 'a', '__dict__'
    def __init__(self, a, b):
        self.a, self.b = a, b
    def __copy__(self):
        return type(self)(self.a, self.b)
    def __deepcopy__(self, memo): # memo is a dict of id's to copies
        id_self = id(self)        # memoization avoids unnecesary recursion
        _copy = memo.get(id_self)
        if _copy is None:
            _copy = type(self)(
                deepcopy(self.a, memo), 
                deepcopy(self.b, memo))
            memo[id_self] = _copy 
        return _copy

참고:deepcopy의 메모 사전을 보관하다id(original)복사본에 대한 (또는 ID 번호)반복적인 데이터 구조로 좋은 행동을 즐기려면 복사본을 만들지 않았는지 확인하고, 복사한 경우 반환하십시오.

그래서 대상을 만들자:

>>> c1 = Copyable(1, [2])

그리고copy다음과 같이 얕게 복사한다.

>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]

그리고deepcopy이제 다음과 같이 복사를 자세히 한다.

>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]

다음이 포함된 얕은 복사본copy.copy()

#!/usr/bin/env python3

import copy

class C():
    def __init__(self):
        self.x = [1]
        self.y = [2]

# It copies.
c = C()
d = copy.copy(c)
d.x = [3]
assert c.x == [1]
assert d.x == [3]

# It's shallow.
c = C()
d = copy.copy(c)
d.x[0] = 3
assert c.x == [3]
assert d.x == [3]

딥 with이 딥(Deep Copy with with)copy.deepcopy()

#!/usr/bin/env python3
import copy
class C():
    def __init__(self):
        self.x = [1]
        self.y = [2]
c = C()
d = copy.deepcopy(c)
d.x[0] = 3
assert c.x == [1]
assert d.x == [3]

설명서: https://docs.python.org/3/library/copy.html

Python 3.6.5에서 테스트됨.

나는 다음은 파이썬에서 분류된 많은 얌전한 사람들과 함께 작동되어야 한다고 믿는다.

def copy(obj):
    return type(obj)(obj)

(물론 나는 여기서 다른 이야기인 "딥 카피"에 대해 말하는 것이 아니다. 그것은 매우 명확한 개념이 아닐 수도 있다. - 얼마나 깊이가 충분한가?)

Python 3과의 나의 테스트에 따르면, 튜플이나 문자열과 같은 불변의 객체에 대해서는 같은 객체를 반환하지만(불변의 객체를 얕게 복사할 필요가 없기 때문에), 목록이나 사전의 경우 독립적인 얕은 복사본을 만든다.

물론 이 방법은 건설업자가 그에 따라 행동하는 계층에만 적용된다.가능한 사용 사례: 표준 Python 컨테이너 클래스의 얄팍한 복사본 만들기.

참조URL: https://stackoverflow.com/questions/4794244/how-can-i-create-a-copy-of-an-object-in-python

반응형