|
| 1 | +# **Standard Library** |
| 2 | + |
| 3 | +Python이 기본 제공하는 모듈들 |
| 4 | + |
| 5 | +## **1. collections** |
| 6 | +Python의 `collections` 모듈은 다양한 데이터 구조를 쉽게 다룰 수 있도록 도와줌. |
| 7 | + |
| 8 | +Counter, defaultdict, deque, OrderedDict, namedtuple 등이 자주 사용된다. |
| 9 | + |
| 10 | +### 1.1 **collections.Counter (요소 개수 세기)** |
| 11 | +리스트 요소의 개수를 쉽게 세는 기능. |
| 12 | + |
| 13 | +#### dict 사용 |
| 14 | +```python |
| 15 | +words = ["apple", "banana", "apple", "cherry", "banana", "apple"] |
| 16 | +word_count = {} |
| 17 | +for word in words: |
| 18 | + if word in word_count: |
| 19 | + word_count[word] += 1 |
| 20 | + else: |
| 21 | + word_count[word] = 1 |
| 22 | +print(word_count) |
| 23 | +``` |
| 24 | + |
| 25 | +- dict를 사용하면 키가 존재하는지 매번 확인해야 하므로 코드가 복잡하고 비효율적. |
| 26 | + |
| 27 | +#### collections.Counter 사용 |
| 28 | +```python |
| 29 | +from collections import Counter |
| 30 | + |
| 31 | +words = ["apple", "banana", "apple", "cherry", "banana", "apple"] |
| 32 | +word_count = Counter(words) |
| 33 | +print(word_count) |
| 34 | +``` |
| 35 | + |
| 36 | +- 내부적으로 최적화되어 있어 요소 개수를 더 빠르고 간결하게 계산. |
| 37 | + |
| 38 | +### 1.2 **collections.deque (빠른 리스트 연산)** |
| 39 | +앞쪽 원소 삽입/삭제 시 `list`는 O(n)이지만 `deque`는 O(1)로 동작. |
| 40 | + |
| 41 | +#### 리스트 사용 (비효율적) |
| 42 | +```python |
| 43 | +lst = [1, 2, 3] |
| 44 | +lst.insert(0, 0) # O(n) 연산 |
| 45 | +lst.pop(0) # O(n) 연산 |
| 46 | +``` |
| 47 | + |
| 48 | +- list는 앞쪽 원소를 삽입/삭제할 때 모든 요소를 이동해야 하므로 O(n) 시간이 걸림. |
| 49 | + |
| 50 | +#### deque 사용 (효율적) |
| 51 | +```python |
| 52 | +from collections import deque |
| 53 | + |
| 54 | +dq = deque([1, 2, 3]) |
| 55 | +dq.appendleft(0) # O(1) |
| 56 | +dq.popleft() # O(1) |
| 57 | +``` |
| 58 | + |
| 59 | +- deque는 양쪽 끝에서 O(1)로 삽입/삭제 가능하여 효율적. |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## **2. itertools** |
| 64 | +반복 가능한 객체를 다루는 다양한 기능 제공. |
| 65 | + |
| 66 | +count, cycle, chain, permutations, starmap 등을 사용하여 반복문과 조건문을 간단하고 효율적으로 처리할 수 있도록 도와준다. |
| 67 | + |
| 68 | +### 2.1 **itertools.permutations (순열 조합 구하기)** |
| 69 | + |
| 70 | +#### 재귀 함수 사용 |
| 71 | +```python |
| 72 | +def permute(arr, path=[]): |
| 73 | + if not arr: |
| 74 | + print(path) |
| 75 | + return |
| 76 | + for i in range(len(arr)): |
| 77 | + permute(arr[:i] + arr[i+1:], path + [arr[i]]) |
| 78 | + |
| 79 | +permute([1, 2, 3]) |
| 80 | +``` |
| 81 | + |
| 82 | +- 재귀 호출로 인해 비효율적이고 코드가 길어짐. |
| 83 | + |
| 84 | +#### itertools.permutations 사용 |
| 85 | +```python |
| 86 | +from itertools import permutations |
| 87 | + |
| 88 | +arr = [1, 2, 3] |
| 89 | +perm_list = list(permutations(arr)) |
| 90 | +print(perm_list) |
| 91 | +``` |
| 92 | + |
| 93 | +- 내부적으로 최적화되어 간결하고 빠름. |
| 94 | + |
| 95 | +### 2.2 **itertools.starmap (튜플 언패킹 최적화)** |
| 96 | +`map()` 대신 사용하면 성능 향상. |
| 97 | + |
| 98 | +#### 일반 map() 사용 |
| 99 | +```python |
| 100 | +def add(a, b): |
| 101 | + return a + b |
| 102 | + |
| 103 | +pairs = [(1, 2), (3, 4), (5, 6)] |
| 104 | +result = list(map(lambda x: add(*x), pairs)) |
| 105 | +``` |
| 106 | + |
| 107 | +- lambda로 언패킹해야 함. |
| 108 | + |
| 109 | +#### starmap() 사용 |
| 110 | +```python |
| 111 | +from itertools import starmap |
| 112 | + |
| 113 | +def add(a, b): |
| 114 | + return a + b |
| 115 | + |
| 116 | +pairs = [(1, 2), (3, 4), (5, 6)] |
| 117 | +result = list(starmap(add, pairs)) |
| 118 | +``` |
| 119 | + |
| 120 | +- 불필요한 lambda 호출을 줄여 성능이 향상됨. |
| 121 | + |
| 122 | +## **3. functools** |
| 123 | +함수 최적화 및 고차 함수 지원. |
| 124 | + |
| 125 | +lru_cache, partial, reduce, update_wrapper, total_ordering 등 여러 고차 함수들을 통해 반복적인 작업을 최적화하고, 코드의 가독성 및 재사용성을 높이는 데 유용하다. |
| 126 | + |
| 127 | +### 3.1 **functools.lru_cache (재귀 최적화)** |
| 128 | + |
| 129 | +#### 사용하지 않음 (느림) |
| 130 | +```python |
| 131 | +def fib(n): |
| 132 | + if n <= 1: |
| 133 | + return n |
| 134 | + return fib(n-1) + fib(n-2) |
| 135 | + |
| 136 | +print(fib(30)) # 매우 느림 |
| 137 | +``` |
| 138 | + |
| 139 | +- 동일한 값을 여러 번 재귀 호출 → 중복 계산 발생 (O(2^n)) |
| 140 | +- 호출 깊이가 커질수록 기하급수적으로 느려짐 |
| 141 | + |
| 142 | +#### lru_cache 사용 (빠름) |
| 143 | +```python |
| 144 | +from functools import lru_cache |
| 145 | + |
| 146 | +@lru_cache(maxsize=None) |
| 147 | +def fib(n): |
| 148 | + if n <= 1: |
| 149 | + return n |
| 150 | + return fib(n-1) + fib(n-2) |
| 151 | + |
| 152 | +print(fib(30)) # 훨씬 빠름 |
| 153 | +``` |
| 154 | + |
| 155 | +- 한 번 계산한 값은 캐싱 → 중복 호출 없이 O(n) |
| 156 | +- 불필요한 연산을 제거해 실행 속도 대폭 향상 |
| 157 | + |
| 158 | +## **4. datetime** |
| 159 | +날짜 및 시간 다루기. |
| 160 | + |
| 161 | +날짜, 시간, 시간 차이, 시간대 변환 등을 손쉽게 처리할 수 있는 기능을 제공한다. |
| 162 | + |
| 163 | +datetime 객체의 메소드를 사용하면 날짜와 시간 연산을 간단하게 할 수 있으며, 다양한 형식으로 날짜와 시간을 출력하거나 변환할 수 있다. |
| 164 | + |
| 165 | +### 4.1 **datetime.datetime (시간 정보 가져오기)** |
| 166 | + |
| 167 | +#### time 사용 |
| 168 | +```python |
| 169 | +import time |
| 170 | + |
| 171 | +timestamp = time.time() |
| 172 | +year = 1970 + timestamp // (365 * 24 * 3600) |
| 173 | +print(f"현재 연도: {int(year)}") |
| 174 | +``` |
| 175 | + |
| 176 | +- Unix 타임스탬프를 직접 변환 → 연도 계산이 번거롭고 가독성 낮음 |
| 177 | + |
| 178 | +#### datetime 사용 |
| 179 | +```python |
| 180 | +from datetime import datetime |
| 181 | + |
| 182 | +now = datetime.now() |
| 183 | +print(f"현재 연도: {now.year}") |
| 184 | +``` |
| 185 | + |
| 186 | +- 즉시 연도 반환 |
| 187 | + |
| 188 | +## **5. pathlib** |
| 189 | +파일 시스템 경로 다루기. |
| 190 | + |
| 191 | +pathlib는 파일 경로를 다루는 다양한 메소드를 제공한다. 예를 들어, joinpath()로 경로를 이어 붙이거나, stem, suffix와 같은 속성을 이용해 파일명이나 확장자도 쉽게 다룰 수 있다. |
| 192 | + |
| 193 | +또한 운영 체제에 맞는 경로 구분자를 자동으로 처리한다. 즉, Windows에서는 백슬래시(\), UNIX-like 시스템에서는 슬래시(/)를 자동으로 다루어 주므로, 플랫폼에 상관없이 코드가 안정적으로 실행된다. |
| 194 | + |
| 195 | +### 5.1 **pathlib.Path (파일 존재 여부 확인)** |
| 196 | + |
| 197 | +#### os 사용 |
| 198 | +```python |
| 199 | +import os |
| 200 | + |
| 201 | +filepath = "example.txt" |
| 202 | +if os.path.exists(filepath): |
| 203 | + print("파일 존재함") |
| 204 | +``` |
| 205 | + |
| 206 | +- 문자열 경로 처리 |
| 207 | + |
| 208 | +#### pathlib.Path 사용 |
| 209 | +```python |
| 210 | +from pathlib import Path |
| 211 | + |
| 212 | +filepath = Path("example.txt") |
| 213 | +if filepath.exists(): |
| 214 | + print("파일 존재함") |
| 215 | +``` |
| 216 | + |
| 217 | +- Path 객체 사용 → 경로 조작이 직관적이고 가독성 향상 |
| 218 | + |
| 219 | +## **6. array** |
| 220 | +메모리 효율적인 배열 사용. |
| 221 | + |
| 222 | +메모리 절약, 인덱스 접근 속도 향상 등의 장점도 있지만 데이터 타입을 고정해야 하므로, 서로 다른 데이터 타입을 저장할 수 있는 리스트보다 유연성이 떨어진다. |
| 223 | + |
| 224 | +### 6.1 **array.array** |
| 225 | + |
| 226 | +#### 리스트 사용 (비효율적) |
| 227 | +```python |
| 228 | +lst = [1, 2, 3, 4, 5] # 객체 포인터 저장 |
| 229 | +``` |
| 230 | + |
| 231 | +- 객체 포인터 저장 → 메모리 사용량 증가 |
| 232 | + |
| 233 | +#### array 사용 (효율적) |
| 234 | +```python |
| 235 | +from array import array |
| 236 | + |
| 237 | +arr = array('i', [1, 2, 3, 4, 5]) # 'i'는 정수(int) 타입 지정 |
| 238 | +``` |
| 239 | + |
| 240 | +- 연속된 메모리 블록 사용 → 메모리 절약, 성능 향상 |
| 241 | + |
| 242 | +## **7. 병렬 처리** |
| 243 | + |
| 244 | +### 7.1 **multiprocessing (CPU 병렬 처리)** |
| 245 | + |
| 246 | +#### 단일 프로세스 실행 (느림) |
| 247 | +```python |
| 248 | +def work(n): |
| 249 | + return sum(i*i for i in range(n)) |
| 250 | + |
| 251 | +nums = [10**6, 10**6, 10**6, 10**6] |
| 252 | +results = [work(n) for n in nums] # 한 개씩 실행 (느림) |
| 253 | +``` |
| 254 | + |
| 255 | +- 한 번에 하나씩 처리 → CPU 코어 활용 부족 |
| 256 | + |
| 257 | +#### multiprocessing 사용 (빠름) |
| 258 | +```python |
| 259 | +from multiprocessing import Pool |
| 260 | + |
| 261 | +def work(n): |
| 262 | + return sum(i*i for i in range(n)) |
| 263 | + |
| 264 | +nums = [10**6, 10**6, 10**6, 10**6] |
| 265 | +with Pool() as pool: |
| 266 | + results = pool.map(work, nums) # 병렬 실행 (빠름) |
| 267 | +``` |
| 268 | + |
| 269 | +- 여러 코어에서 병렬 실행 → 실행 속도 향상 |
| 270 | + |
| 271 | +### 7.2 **concurrent.futures.ThreadPoolExecutor (I/O 최적화)** |
| 272 | + |
| 273 | +#### 단일 스레드 실행 (느림) |
| 274 | +```python |
| 275 | +import requests |
| 276 | + |
| 277 | +urls = ["https://example.com"] * 10 |
| 278 | + |
| 279 | +for url in urls: |
| 280 | + response = requests.get(url) |
| 281 | + print(response.status_code) |
| 282 | +``` |
| 283 | + |
| 284 | +- 한 번에 하나씩 처리 → I/O 작업에 시간이 많이 소요됨 |
| 285 | + |
| 286 | +#### ThreadPoolExecutor 사용 (빠름) |
| 287 | +```python |
| 288 | +from concurrent.futures import ThreadPoolExecutor |
| 289 | +import requests |
| 290 | + |
| 291 | +urls = ["https://example.com"] * 10 |
| 292 | + |
| 293 | +with ThreadPoolExecutor() as executor: |
| 294 | + results = executor.map(requests.get, urls) |
| 295 | + |
| 296 | +for response in results: |
| 297 | + print(response.status_code) |
| 298 | +``` |
| 299 | + |
| 300 | +- 여러 스레드에서 병렬 실행 → I/O 대기 시간 동안 다른 요청 처리 가능, 속도 향상 |
0 commit comments