시작하기 전
다음의 내용을 이해하고 보길 바람.
[Py] 객체(object)에 대한 정보 확인하기
Python에서 object(객체)란?type, id, refcount, value 를 속성으로 가지고 있는 a chunk of data.https://dsaint31.tistory.com/517 [Python] Variable (and Object)Variable (and Object)1. 정의Python에서 Variable은 Memory에 할당된 Object
ds31x.tistory.com
[Python] mutable and immutable: Mutability
MutabilityPython에서 Data Types를 구분짓는 중요 속성. Python에서 Object 는id,type,value,reference count를 가지는데,이 중 value를 변경할 수 있는지를 나타내는 것이 바로 mutability임. Mutable인 type의 object(객체)는
ds31x.tistory.com
is와 ==의 차이점 기억할 것: https://ds31x.tistory.com/54
[Python] Boolean Operators, Relational Operators, Membership Operators and Identity Operator
https://dsaint31.tistory.com/516 -(negation) > * = / = // = % > + = -(subtraction) Lower우선순위를 기억하는 것도 중요하지만, 헷갈리면 그냥 parentheses로 묶어주면 된다. (가독성을 위해서도 " data-og-host="dsaint31.tistory
ds31x.tistory.com
예제 코드를 https://pythontutor.com/ 을 통해 실행해보면 보다 이해가 쉬움:
Python Tutor - Python Online Compiler with Visual AI Help
Online Compiler, AI Tutor, and Visual Debugger for Python, Java, C, C++, and JavaScript Python Tutor helps you do programming homework assignments in Python, Java, C, C++, and JavaScript. It contains a step-by-step visual debugger and AI tutor to help you
pythontutor.com
Shallow Copy와 Deep Copy
Python에서 assignment를 수행될 때,
- 오른쪽이 reference (즉 variable이 =연산자 우측에 있음)인 경우
- 기본적으로 Shallow Copy가 발생한다.
하지만 특정 경우에는 Deep Copy 가 필요한 경우가 있기 때문에 이 둘의 차이를 명확히 알고 있는 것이 중요하다.
이 둘의 차이는 다음 그림이 간략하게 설명해 준다.
Shallow copy가 일어났다면
- 왼쪽의 경우처럼 실제 데이터가 있는 메모리영역 Referenced Object가 공유되고
- 이를 참조하는 새로운 Cloned Object가 만들어진다.
때문에 실제로는 같은 Object를 가리키고 있기 때문에
- Original Object에서 수정이 일어나면
- 해당 수정사항이 Cloned Object를 통해 접근하는 경우에도 똑같이 반영이 된다.
Deep copy는
- copy가 일어나는 시점에 똑같은 값을 가지는 Object를 새로 생성하고
- 해당 새로 생성된 Object를 가리키게 한다.
때문에 이후로는 각각의 reference가 다른 memory 영역을 가리키므로 한쪽의 수정이 다른 쪽에는 반영이 되지 않는다.
일반적으로 매우 큰 메모리를 차지하고 있는 object나
dynamic programming 등에서 사용되는 object 들은 shallow copy가 유용하지만,
값만 똑같고 다른 메모리 영역에 새로 할당을 꼭 해야 하는 경우나
원본은 보존하고 원본에 대한 복사본에서 처리를 하는 경우 등에는
deep copy가 꼭 필요하다.
Assignment=같은 object를 가리킴, Copy Constructor=Mutability에 따라 다름.
Python에서 assignment는
- 왼쪽 variable (or name, reference)이 오른쪽에 놓인 value(or Object)를 참조하도록 하는 것으로
- 오른쪽 expression의 최종값을 value로 가지는 Object를 왼쪽의 variable이 가리키도록(refer to) 할당(=해당 object를 참조).
2023.06.13 - [Programming] - [Python] Variable (and Object)
[Python] Variable (and Object)
Python에서 Variable은 Memory에 할당된 Ojbect를 참조하는 Name (=Reference)에 불과하다. 이 문서에서 Object는 Python에서의 Object로 type과 value, ID (CPython에서는 할당된 memory address), 그리고 reference count를 가지
dsaint31.tistory.com
즉, variable(or reference)이 assignment에서 오른쪽 operand인 경우,
왼쪽 operand인 variable(or reference)도 같은 object를 참조하게 된다.
immutable object에 대한 variable 이 우측 operand인 경우.
다음 예제 코드는 오른쪽 operand인 variaible이 immutable
object를 참조하는 경우이며 d0
와 d1
가 가리키는 object들이 같은 ID를 가지게 됨(=같은 Object 참조)
# 단순 assignment는 같은 object를 가리킴.
d0 = (1,2,3)
d1 = d0
print(f'id of d0:{id(d0)}, id of d1:{id(d1)}')
결과는 다음과 같음.
id of d0:140488388961920, id of d1:140488388961920
d1 is d0 : True
d1 == d0 : True
tuple은 immutable.
주의할 것은 immutable
object의 copy constructor
를 assignment의 오른쪽 operand로 놓은 경우도 같은 object를 가리키게 된다는 점이다. (생성을 하는 것처럼 보이지만... 변경불가의 object를 굳이 다시 만들 필요가 없으므로)
d2 = tuple(d0)
print(f'id of d2:{id(d2)}')
print(f'd1 is d0 : {d1 is d0}')
print(f'd1 == d0 : {d1 == d0}')
결과는 다음과 같음.
id of d2:140488388961920
d1 is d0 : True
d1 == d0 : True
mutable object에 대한 variable 이 우측 operand인 경우.
Mutable
의 경우도 단순 assignment는 같은 memory 영역을 가리킴 (Variable은 단순 reference임을 잊지 말자).
# Muutable obj.는 shallow copy!
d0 = [1,2,3]
d1 = d0
print(f'id of d0:{id(d0)}, id of d1:{id(d1)}')
print(f'd1 is d0 : {d1 is d0}')
print(f'd1 == d0 : {d1 == d0}')
결과는 다음과 같음.
id of d0:140489189478208, id of d1:140489189478208
d1 is d0 : True
d1 == d0 : True
단, immutable
의 경우와 달리 mutable
object에 대한 variable을 이용한 copy constructor에서는 새로 memory할당이 된 object를 가리키게 된다.
d2 = list(d0)
print(f'id of d2:{id(d2)}')
print(f'd1 is d0 : {d2 is d0}')
print(f'd1 == d0 : {d2 == d0}')
결과
id of d2:140650393264576
d1 is d0 : False
d1 == d0 : True
[:]
slicing을 이용한 경우
immutable
의 경우엔 단순히 assignment 한 것과 같은 결과 이지만, mutable
인 경우엔 다른 메모리 영역에 새로 할당 이 이루어진다.
주의할 것은 deep copy는 아니라는 점임.
immutable의 경우
d0 = ([1,2,3],1,2,3) #Immutable
d1 = d0[:]
print(f'id of d0:{id(d0)}, id of d1:{id(d1)}')
print(f'd1 is d0 : {d1 is d0}')
print(f'd1 == d0 : {d1 == d0}')
결과
id of d0:140488387426592, id of d1:140488387426592
d1 is d0 : True
d1 == d0 : True
mutable의 경우
d0 = [[1,2,3],1,2,3] # mutable
d1 = d0[:]
print(f'id of d0:{id(d0)}, id of d1:{id(d1)}')
print(f'd1 is d0 : {d1 is d0}')
print(f'd1 == d0 : {d1 == d0}')
결과
id of d0:140488387495104, id of d1:140488387053504
d1 is d0 : False
d1 == d0 : True
주의할 것은 item이 list
와 같은 mutable collection인 경우 item 들이 새로 만들어지는 것은 아니라는 점이다.
d0 = [[1,2,3],1,2,3]
d1 = d0[:]
d1[0][0] = 777
print(f'd0:{d0}\nd1:{d1}')
결과
d0:[[777, 2, 3], 1, 2, 3]
d1:[[777, 2, 3], 1, 2, 3]
앞서 본 것처럼 d0
와 d1
은 다른 메모리 영역(list
를 위해 할당된)을 가리키나,
해당 list
의 index 0인 item이 mutable
인 [1,2,3]
list이며 이는 d0
와 d1
이 공유하고 있다.
때문에 한 쪽을 수정할 경우 다른 쪽에도 영향을 주어 777
로 바뀐 것을 볼 수 있음.
즉, shallow copy가 이루어진 것임.
만약 item이 immutable collection이라면?
immutable collection은 수정이 안되기 때문에 변경이 이루어지면 그냥 새로 생성하여 할당이 된다. 때문에 shallow copy이지만 마치 deep copy처럼 변경된 것으로 보일 수 있으나, 해당 item에 처리가 이루어질 때 아예 다른 object가 만들어져서 재할당된 것이지 앞서의 assignment에서 deep copy가 된 건 아님.
d0 = [(1,2,3),1,2,3]
d1 = d0[:] # 이 시점까지 shallow copy로 ,d0와 d1모두 같은 (1,2,3) object를 가르킴.
print (d0[0] is d1[0])
d1[0] += (4,5) # tuple에 대한 augmented assignment는 새로운 object를 생성하고 재할당임.
print (d0[0] is d1[0])
print(f'd0:{d0}\nd1:{d1}')
결과는 다음과 같음.
True
False
d0:[(1, 2, 3), 1, 2, 3]
d1:[(1, 2, 3, 4, 5), 1, 2, 3]
copy
메서드를 이용한 경우 (=shallow copy)
immutable object들에서는 copy
메소드가 지원되지 않으며, mutable object에서만 지원함.
기본적으로 새로운 메모리 영역을 할당하지만, item으로 있는 mutable
object들은 공유를 하기 때문에 shallow copy임.
위의 그림에서 왼쪽에 해당하며,bag0
에 대해 shallow copy를 수행한 bag1
경우처럼 item들은 새로 만들어지는 것이 아니다.
a = [[1,2,3],'test']
b = a.copy()
print(f'a is b:{a is b}')
b[0][0]=77
print(f'a is {a}\nb is {b}')
결과는 다음과 같음
a is b:False
a is [[77, 2, 3], 'test']
b is [[77, 2, 3], 'test']
deep copy : copy 모듈의 deepcopy() 함수
mutable
object가 item인 collection 객체들에 대해 deep copy를 하기 위해선 copy
모듈의 deepcopy
함수를 사용한다.
다음 예제 코드를 참고하라.
import copy
a = [[1,2,3],'test']
c = copy.deepcopy(a)
c[0][0] = 77
print(f'a is {a}\nb is {c}')
결과는 다음과 같다
a is [[1, 2, 3], 'test']
b is [[77, 2, 3], 'test']
literal의 경우
기본적으로 literal로 할당하는 경우는 다른 객체를 가리키게 된다(값이 같더라도...)
하지만, Python의 경우 memory의 효율적 사용을 위해서
literal 및 constant 등에 대해선 copy constructor
와 같이 동일한 memory 영역을 가리키는 형태로 처리함:
작은 정수 (-5~256) 이거나 특정 규칙을 따르는 짧은 문자열의 경우 PVM이 미리 생성하여 캐싱.
- [-5,256] 범위의 정수에 대한 이같은 처리를 integer caching이라고 부름.
- 특정 규칙을 따르는 문자열을 resue하는 처리는 Automate String Interning이라고 부름(아래 url참고)
literal이란:
2023.02.20 - [Programming] - [Basic] Literal
[Basic] Literal
Literal소스 코드 상에서 고정된 값을 가르킴. (또는 고정된 값을 나타내는 표기법을 의미함.)Programming language에서 data의 값을 지정(specifying data values)하는 방법은 다음 중의 하나임.1. Literal을 사용.2
dsaint31.tistory.com
String Interning이란?
https://ds31x.tistory.com/472
[Py] String Interning
Intern(인터닝)은 Python에서 문자열 최적화 기법의 하나로서,동일한 문자열을 메모리에 한 번만 저장하고 여러 변수가 같은 객체를 참조하도록 하는 기법을 가리킴.# Normal case (not interned)a = "hello wor
ds31x.tistory.com
다음 예제 코드를 참고하라.
a = 7
b = 7
print(f'a is b: {a is b}')
c = b
print(f'c is a: {c is a}')
결과는 다음과 같음.
a is b: True
c is a: True
memory의 효율적 사용을 위해서 많이 사용되는 일부 literal
및 copy constructor
에선 shallow copy와 같이 같은 memory의 영역을 가리키게 됨.
물론 명시적으로 다음과 같이 값만 같은 tuple
을 따로 할당 하면 다른 memory 영역에 생성 됨
(integer caching 및 automatic string interning 을 제외하고, literal
로 명시적 할당은 다른 객체를 가리키게 됨.)
a = (1,2)
b = (1,2)
print( f'a is b :{a is b} / a == b : {a ==b}')
결과
a is b :False / a == b : True
같이보면 좋은 자료
[Python] Arithmetic, Variables, Types and Assignment
Numeric Type and Arithmetic in Python (+Augmented Assignment)https://dsaint31.tistory.com/516 -(negation) > * = / = // = % > + = -(subtraction) Lower우선순위를 기억하는 것도 중요하지만, 헷갈리면 그냥 parentheses로 묶어주면 된다
ds31x.tistory.com
'Programming' 카테고리의 다른 글
[Python] Iterable and Iterator, plus Generator (1) | 2023.06.07 |
---|---|
[Python] Comprehension (list, dict, set) and Generator Expression (0) | 2023.06.06 |
[Programming] Garbage Collection (GC) (0) | 2023.06.05 |
[Python] Interpreter and PVM (Python Virtual Machine) (2) | 2023.06.05 |
[Python] recursive call : Fibonacci Sequence (and dynamic programming) (0) | 2023.05.24 |