-
파이썬 심화: 변수와 메모리python 2022. 2. 12. 22:42
Reference Counting
- 파이썬은 객체가 참조될 때마다 ref_count를 +1한다.
- 0이 되면 python memory manager가 객체를 메모리에서 삭제함. (할당 해제)
import sys my_var = [1,2,3] sys.getrefcount(my_var)
Garbage Collection
- 순환참조의 경우 ref_count는 절대 0이 되지 않는다.
- 이 경우 referece counting을 통해 python memory manager가 객체를 메모리에서 삭제할 수 없음. -> memory leak 발생
- GC는 순환참조인 것들을 메모리에서 지워주는 역할을 한다.
- gc는 기본적으로 turn on 상태다.
- gc 모듈을 사용해서 gc를 끄거나 수동실행 등 조작할 수 있다.
Variable Re-assignment
- 변수에 값을 재할당하면 새로운 주소에 값이 할당된다.
- 따라서 변수 reference 값도 새로운 주소를 향하게 바뀐다.
>>> a = 10 >>> hex(id(a)) '0x7fb38df09490' >>> a = 15 >>> hex(id(a)) '0x7fb38df09418'
fun fact
- in fact, the value inside the int objects, can never be changed
>>> a = 10 >>> b = 10 >>> hex(id(a)) '0x7fb38df09490' >>> hex(id(b)) '0x7fb38df09490'
object mutability
Immutable
- Numbers(int, float, Booleans, etc)
- strings
- Tuples
- Frozen Sets
- User-Defined Classes
Mutable
- Lists
- Sets
- Dictionaries
List에는 append해도 아이디가 바뀌지 않음! >>> my_list = [1,2,3] >>> id(my_list) 4443124008 >>> my_list.append(4) >>> my_list [1, 2, 3, 4] >>> id(my_list) 4443124008 + 연산을 하면 새로운 리스트가 생기기 때문에 id값이 바뀜. >>> my_list = [1,2,3] >>> id(my_list) 4443244880 >>> my_list = my_list + [4] >>> my_list [1, 2, 3, 4] >>> id(my_list) 4443244808
tuple
- immutable이지만 mutable을 원소로 가질 수 있다.
Function args and Mutability
- Immutable objects are safe from unintended side-effects
- Mutable objects are not safe from unintended side-effects
Shared refereces and mutability
>>> a = "hi" >>> b = "hi" >>> id(a) == id(b) True >>> a = [1,2,3] >>> b = [1,2,3] >>> id(a) == id(b) False >>> a = [1,2,3] >>> b = a >>> id(a) == id(b) True >>> b.append(100) >>> a [1, 2, 3, 100] >>> b [1, 2, 3, 100]
Variable Equality
- Memory Address가 같냐, Object State가 같냐로 나눌 수 있다.
- Memory Address는 is연산
- Object State 는 ==연산으로 비교한다.
None Object
- None 은 실제 python memory manger가 관리하는 실제 object다.
- the memmory manager will always use a shared reference when assigning a variable to None
- 즉, a, b, c 값이 모두 None이면 이 세개의 주소값을 모두 같다.
>>> a = 10 >>> b = a >>> a is b True >>> a == b True >>> a = 1 >>> b = 1 >>> a == b True >>> a is b True >>> >>> >>> a = 500 >>> b = 500 >>> a == b True >>> a is b False >>> a = [1,2,3] >>> b = [1,2,3] >>> a is b False >>> a == b True >>> a = "a" >>> b = "a" >>> a is b True >>> a == b True >>> >>> >>> a = "asdfj23ks" >>> b = "asdfj23ks" >>> a is b True >>> a == b True >>> a = 10 >>> b = 10.0 >>> a is b False >>> a == b True
Everything is an object
- int, bool, string, list.....operators(+, -, ...), functions, class, types.. 등등 파이썬에서 모든것은 object다.
- this means they all have a memory address
- Any object can be assigned to a variable
- Any object can be passed to a function
- Any object can be returned from a function
Python Optimizations: Interning
- a, b 에 10을 할당하고 a is b를 하면 True인데, 500을 할당하면 a is b는 False다. 이유는??!
interning: reusing objects on-demand
- at startup, python pre-loads(caches) a global list of integers in the range[-5, 256]
- Anytime an int is referenced in that range, python will use the cached version of that object
- this is optimization strategy - small integers show up often
>>> a = 10 >>> b = 10 >>> a is b True >>> a = 1000 >>> b = 1000 >>> a is b False
Python Optimizations: String Interning
str형태가 아래 조건일 때(=identifiers처럼 생겼을 때) 파이썬은 interning을 한다
- must start with _ or a letter
- can only contain _, letters and numbers
- 예시
- "hello_world": interning O
- "hello world": interning X
interning은 speed, memory optimization을 위해 파이썬이 자동으로 한다.
수동으로도 할 수 있는데, `sys.intern("hello world") 형태로 가능하다.
언제 수동으로 사용하면 좋을까?
- 아주 큰 str을 아주 반복적으로 다뤄야 할 때.
- str comparision을 아주 많이 할때.
- 정말 필요해서가 아니면 굳이 하지 말아라.
예시
>>> a = "hello_world" >>> b = "hello_world" >>> a is b True >>> >>> a = "hello world" >>> b = "hello world" >>> a is b False
sys.intern 예시
>>> import sys >>> a = sys.intern("hello world") >>> b = sys.intern("hello world") >>> c = ("hello world") >>> a is b True >>> b is c False
sys.intern 시간 비교 예시
import sys import time def compare_using_equals(n): a = "hello world" * 200 b = "hello world" * 200 for i in range(n): if a == b: pass def compare_using_interning(n): a = sys.intern("hello world" * 200) b = sys.intern("hello world" * 200) for i in range(n): if a is b: pass start = time.perf_counter() compare_using_equals(30000000) end = time.perf_counter() print(end-start) start = time.perf_counter() compare_using_interning(30000000) end = time.perf_counter() print(end-start) 1.119146882 0.8879429629999998
'python' 카테고리의 다른 글
파이썬 클린코드 3 (0) 2022.02.26 파이썬 심화: function parameter (0) 2022.02.12 파이썬 클린코드 2 (0) 2022.02.12 파이썬 클린코드 1 (0) 2022.02.12 엄청 쉬운 python 파일 쓰기, 파일 읽기, 사진 다운받기 (0) 2021.04.06