Customized class deep copy

참조
python의 built-in object들은 모두 기본적으로 copy 모듈의 deepcopy 함수를 통해서 깊은 복사가 가능하다.
하지만 customized class들에 대해서는 직접 정의를 해주어야 한다.

아래의 예시를 보면 assigned operator를 사용했을 때 얕은 복사가 되는 것을 알 수 있다.

In [19]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class AA(object):
    def __init__(self, lst, dct):
        self.lst = lst
        self.dct = dct

lst1 = [i for i in range(0, 10)]
dct1 = {i:chr(i) for i in range(0, 10)}

a1 = AA(lst1, dct1)
a2 = a1
a3 = AA(lst1, dct1)

## a1과 a2가 같은 객체와 binding됨. 
print(id(a1), id(a2), id(a3))

## 또한, a1과 a3가 메모리 주소가 달라서 다를 것으로 알기 쉽지만, 내부 변수의 메모리 주소는 같음 
## 즉, shallow copy된 것 
print(id(a1.lst), id(a2.lst), id(a3.lst))

# a2 만 바꾸었을 뿐인데 a1도 바뀜
a2.lst = [a+5 for a in a2.lst]
print(a1.lst)
print(a2.lst)
1
2
3
4
5
140235648944224 140235648944224 140235784917400
140235784718280 140235784718280 140235784718280
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]


Copy method함수 만들기

직접 class 내부에 정의해 주기로 하자.

만약 외부 모듈을 사용한다면 그 모듈을 상속받아서 재정의를 해주어야 한다.

In [18]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class AA(object):
    def __init__(self, lst, dct):
        self.lst = lst
        self.dct = dct
        
    def copy(self):
        ## 모든 attribute에 대해서 copy해줘야 함
        return AA(self.lst.copy(), 
                  self.dct.copy())

a1 = AA(lst1, dct1)
a2 = a1.copy()
a3 = a1.copy()
print(id(a1), id(a2), id(a3))
print(id(a1.lst), id(a2.lst), id(a3.lst))
a2.lst = [a+5 for a in a2.lst]
print(a1.lst)
print(a2.lst)
1
2
3
4
5
140235784917400 140235784917512 140235784830256
140235785127880 140235784718280 140235784712264
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]


deecopy 모듈 사용하기

In [23]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import copy

class AA(object):
    def __init__(self, lst, dct):
        self.lst = lst
        self.dct = dct
    
a1 = AA(lst1, dct1)
## 그냥 아래처럼 copy.deepcopy를 사용하면 다 해결되긴 합니다. 
## shallow copy: copy.copy()
a2 = copy.deepcopy(a1)
a3 = copy.deepcopy(a2)
print(id(a1), id(a2), id(a3))
print(id(a1.lst), id(a2.lst), id(a3.lst))
a2.lst = [a+5 for a in a2.lst]
print(a1.lst)
print(a2.lst)
1
2
3
4
5
140235649029680 140235784722360 140235785284072
140235784718280 140235311756424 140235311814024
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]


basic class를 만들고 모두 상속받는 식으로 할 수도 있다.

In [22]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import copy
import numpy as np 

class obj(object): 
    def copy1(self):
        ## __class__(): 마치 cls를 넘겨받는 것처럼 해당 클래스를 생성해줄 수 있습니다. 
        ## self__dict: 내부의 attribute과 각 값ㅇ 접근할 수 있습니다. 
        ## **dict: dictionary 앞에 **를 붙이면, key=value의 형태로 함수에 바로 넘겨줄 수 있습니다. 
        ## 하지만 이 경우에도 해당 class의 내부 attribute에 대해서는 deep copy가 안됩니다. 
        return self.__class__(**self.__dict__)

    def copy2(self):
        ## 이렇게 해당 딕셔너리의 각 v에 deepcopy를 해서 복제해줘도 됩니다. 
        return self.__class__(**{k: copy.deepcopy(v) for k, v in self.__dict__.items()})
        
    def copy3(self):
        ## 근데..그냥 copy module을 사용합시다. 
        return copy.deepcopy(self)
    
class AA(obj):
    def __init__(self, lst):
        self.lst = lst
        
lst = [1,2 , 3, 4, 5]
a1 = AA(lst)
a2 = a1.copy1()
print(id(a1), id(a2))
print(id(a1.lst), id(a2.lst))
a2.lst = [a+5 for a in a2.lst]
print(a1.lst)
print(a2.lst)
print("="*21)

a2 = a1.copy2()
print(id(a1), id(a2))
print(id(a1.lst), id(a2.lst))
a2.lst = [a+5 for a in a2.lst]
print(a1.lst)
print(a2.lst)
print("="*21)

a2 = a1.copy3()
print(id(a1), id(a2))
print(id(a1.lst), id(a2.lst))
a2.lst = [a+5 for a in a2.lst]
print(a1.lst)
print(a2.lst)
print("="*21)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
140235118754336 140235118754392
140235311756936 140235311756936
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
=====================
140235118754336 140235311730472
140235311756936 140235311816200
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
=====================
140235118754336 140235648943664
140235311756936 140235311813960
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
=====================

Leave a comment