최근 Python의 기초 ~ 고급까지를 커버하는 가벼운 강의를 수강하면서 내용을 정리해 보고 있다.
대부분은 아는 내용이지만 중간 중간 정리가 필요한 내용들이 있어서, 오늘부터 정리를 해 나갈 예정. 그리고 가급적 Python의 공식 documentaion을 보면서 정리를 하려고 한다. 앞으로 습관을 이렇게 만들어야지.
첫 번째로 정리할 내용은 assignment(할당)와 copy(복사)다.
실제로 데이터 분석을 하다 보면, copy나 assignment를 잘못 써서 원본 데이터를 건드리는 경우가 많은데, 정확히 assignment(할당)와 copy(복사)가 어떤 식으로 이루어지는지 알 필요가 있다.
01. assignment
우선 ' = ' 표시로 변수에 값을 할당하는 것은 복사가 아니다.
Python 공식 문서에서는 이렇게 표현하고 있다.
= "Assignment statements in Python do not copy objects, they create bindings between a target and an object."
즉, target과 object를 연결만 할 뿐! 이라는 것.
colors = ['red', 'blue', 'green']
b = colors # b도 colors를 pointing 하고 있는 것
b.append('white')
print(b)
print(colors)
b와 colors가 바라보고 있는 list는 동일한 object이다.
b와 color는 변수만 다를 뿐, list가 저장되어 있는 메모리를 동일하게 pointing 하고 있다.
그래서 b에 append를 하면, colors를 print 했을 때에도 'white'가 추가되어 있는 것을 볼 수 있다.
습관적으로 raw data를 어떤 변수에 저장해 두고, 다른 변수에 이걸 ' ='로 할당해서 이것 저것 작업을 하곤 raw data가 변해서 놀랐던 적이 있었는데, 근본 없이 파이썬을 공부하면 예전의 실수를 반복하게 된다..
02. shallow copy (얕은 복사)
앞서 이야기한 단순한 assignment보다 더 나은 접근은 shallow copy(얕은 복사)이다.
공식 문서에서는 이렇게 이야기하고 있다.
: A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
a = [[1, 2], [2, 4]]
b = a[:] ## shallow copy
## 새로운 object를 만들지만 내부 요소들은 원래의 것을 pointing 하고 있음
b.append([3, 6])
print(b)
print(a)
b[0].append(3)
print(b)
print(a)
결과를 살펴 보면, b에서만 append가 적용되어서 [3, 6] 이 추가 된 것을 알 수 있다.
하지만, b[0].append(3)를 하면 a 를 print 했을 때에도 변화가 이루어진다.
즉, shallow copy(얕은 복사)는 새로운 object를 만들지만 내부 요소들의 주소는 원래의 것을 pointing 하고 있게 된다. 그래서 b[0] 과 같이 내부 요소에 접근하는 순간, a도 함께 변하는 것.
구조 자체가 단순한 object인 경우에는 크게 상관이 없겠지만(= 단순한 list인 경우에는 deep copy와 같은 움직임), shallow copy는 이런 특징이 있다는 걸 알아두어야 겠다.
한편, [:] 꼴이 아니라, copy.copy()를 사용해도 된다.
03. deep copy (깊은 복사)
마지막으로 깊은 복사(deep copy)는 공식 문서에서 이렇게 표현하고 있다.
: A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
즉, 새로운 object를 만들고 그 안의 요소들도 모두 복사하게 된다. 말 그대로 진짜 copy인 셈.
a = [[1, 2], [2, 4]]
import copy
b = copy.deepcopy(a) ## deep copy: totally different object
## 구조 자체를 모두 copy 하게 됨.
b[0].append(4)
print(b)
print(a)
짜잔.
shallow copy때와 같은 방식으로 코드를 작성해 보았는데, 여기에서는 b의 첫 번째 요소에만 append가 이루어진 것을 볼 수 있다.
※ 오늘 참고한 python documentation 링크는 여기: https://docs.python.org/3.8/library/copy.html
copy — Shallow and deep copy operations — Python 3.8.17 documentation
copy — Shallow and deep copy operations Source code: Lib/copy.py Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes need
docs.python.org
dataframe에서의 copy(복사)는?
궁금해서 pandas의 공식 문서를 찾아 보았는데
pandas.DataFrame.copy — pandas 2.0.3 documentation
previous pandas.DataFrame.convert_dtypes
pandas.pydata.org
기본적으로 dataFrame 객체에서 copy method를 사용하면 된다.
"When deep=True (default), a new object will be created with a copy of the calling object’s data and indices. Modifications to the data or indices of the copy will not be reflected in the original object (see notes below)."
deep = True 옵션은 default로 들어가 있고, 원본 객체를 건드리지 않고 수정을 할 수 있게 해준다.
다만 아래와 같이 notes가 나와있다.
"When deep=True, data is copied but actual Python objects will not be copied recursively, only the reference to the object. This is in contrast to copy.deepcopy in the Standard Library, which recursively copies object data (see examples below)."
deep = True 옵션을 사용하는 경우, Python standard Library에서처럼 내부 요소들까지 deepcopy가 구현되는 것은 아닌 것으로 보인다. 객체의 데이터와 index는 복사 된다. 하지만 내부 요소들은 복사되지 않는다.
import pandas as pd
s = pd.Series([[1, 2], [3, 4]])
deep = s.copy()
s[0][0] = 10
print("s: ", s)
print("============")
print("deep: ", deep)
deep의 [0][0]도 10으로 변한 것을 알 수 있음 ㅎ
조금 헷갈리지만 조심해서 다루면 어려울 건 없어 보인다.
'Pyhon 기초, 실전' 카테고리의 다른 글
[Python 기초] list, dictionary comprehension and conditional comprehension (1) | 2023.07.17 |
---|---|
[Python 기초] 여러 가지 파일 읽고 쓰기 (txt, csv, pickle, json 등) (0) | 2023.07.16 |
[Python 기초] set과 tuple 그리고 tuple의 packing, unpacking (0) | 2023.07.14 |
[Python 기초] 주석(Docstring) 작성 스타일 (0) | 2023.07.13 |
[Python 기초] 변수의 범위(scope), nonlocal과 global 키워드 사용법 (0) | 2023.07.12 |