Skip to content

Standard Library

Python이 기본 제공하는 모듈들

1. collections

Python의 collections 모듈은 다양한 데이터 구조를 쉽게 다룰 수 있도록 도와줌.

Counter, defaultdict, deque, OrderedDict, namedtuple 등이 자주 사용된다.

1.1 collections.Counter (요소 개수 세기)

리스트 요소의 개수를 쉽게 세는 기능.

dict 사용

words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
word_count = {}
for word in words:
    if word in word_count:
        word_count[word] += 1
    else:
        word_count[word] = 1
print(word_count)
  • dict를 사용하면 키가 존재하는지 매번 확인해야 하므로 코드가 복잡하고 비효율적.

collections.Counter 사용

from collections import Counter

words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
word_count = Counter(words)
print(word_count)
  • 내부적으로 최적화되어 있어 요소 개수를 더 빠르고 간결하게 계산.

1.2 collections.deque (빠른 리스트 연산)

앞쪽 원소 삽입/삭제 시 list는 O(n)이지만 deque는 O(1)로 동작.

리스트 사용 (비효율적)

lst = [1, 2, 3]
lst.insert(0, 0)  # O(n) 연산
lst.pop(0)  # O(n) 연산
  • list는 앞쪽 원소를 삽입/삭제할 때 모든 요소를 이동해야 하므로 O(n) 시간이 걸림.

deque 사용 (효율적)

from collections import deque

dq = deque([1, 2, 3])
dq.appendleft(0)  # O(1)
dq.popleft()  # O(1)
  • deque는 양쪽 끝에서 O(1)로 삽입/삭제 가능하여 효율적.

2. itertools

반복 가능한 객체를 다루는 다양한 기능 제공.

count, cycle, chain, permutations, starmap 등을 사용하여 반복문과 조건문을 간단하고 효율적으로 처리할 수 있도록 도와준다.

2.1 itertools.permutations (순열 조합 구하기)

재귀 함수 사용

def permute(arr, path=[]):
    if not arr:
        print(path)
        return
    for i in range(len(arr)):
        permute(arr[:i] + arr[i+1:], path + [arr[i]])

permute([1, 2, 3])
  • 재귀 호출로 인해 비효율적이고 코드가 길어짐.

itertools.permutations 사용

from itertools import permutations

arr = [1, 2, 3]
perm_list = list(permutations(arr))
print(perm_list)
  • 내부적으로 최적화되어 간결하고 빠름.

2.2 itertools.starmap (튜플 언패킹 최적화)

map() 대신 사용하면 성능 향상.

일반 map() 사용

def add(a, b):
    return a + b

pairs = [(1, 2), (3, 4), (5, 6)]
result = list(map(lambda x: add(*x), pairs))
  • lambda로 언패킹해야 함.

starmap() 사용

from itertools import starmap

def add(a, b):
    return a + b

pairs = [(1, 2), (3, 4), (5, 6)]
result = list(starmap(add, pairs))
  • 불필요한 lambda 호출을 줄여 성능이 향상됨.

3. functools

함수 최적화 및 고차 함수 지원.

lru_cache, partial, reduce, update_wrapper, total_ordering 등 여러 고차 함수들을 통해 반복적인 작업을 최적화하고, 코드의 가독성 및 재사용성을 높이는 데 유용하다.

3.1 functools.lru_cache (재귀 최적화)

사용하지 않음 (느림)

def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

print(fib(30))  # 매우 느림
  • 동일한 값을 여러 번 재귀 호출 → 중복 계산 발생 (O(2^n))
  • 호출 깊이가 커질수록 기하급수적으로 느려짐

lru_cache 사용 (빠름)

from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

print(fib(30))  # 훨씬 빠름
  • 한 번 계산한 값은 캐싱 → 중복 호출 없이 O(n)
  • 불필요한 연산을 제거해 실행 속도 대폭 향상

4. datetime

날짜 및 시간 다루기.

날짜, 시간, 시간 차이, 시간대 변환 등을 손쉽게 처리할 수 있는 기능을 제공한다.

datetime 객체의 메소드를 사용하면 날짜와 시간 연산을 간단하게 할 수 있으며, 다양한 형식으로 날짜와 시간을 출력하거나 변환할 수 있다.

4.1 datetime.datetime (시간 정보 가져오기)

time 사용

import time

timestamp = time.time()
year = 1970 + timestamp // (365 * 24 * 3600)
print(f"현재 연도: {int(year)}")
  • Unix 타임스탬프를 직접 변환 → 연도 계산이 번거롭고 가독성 낮음

datetime 사용

from datetime import datetime

now = datetime.now()
print(f"현재 연도: {now.year}")
  • 즉시 연도 반환

5. pathlib

파일 시스템 경로 다루기.

pathlib는 파일 경로를 다루는 다양한 메소드를 제공한다. 예를 들어, joinpath()로 경로를 이어 붙이거나, stem, suffix와 같은 속성을 이용해 파일명이나 확장자도 쉽게 다룰 수 있다.

또한 운영 체제에 맞는 경로 구분자를 자동으로 처리한다. 즉, Windows에서는 백슬래시(), UNIX-like 시스템에서는 슬래시(/)를 자동으로 다루어 주므로, 플랫폼에 상관없이 코드가 안정적으로 실행된다.

5.1 pathlib.Path (파일 존재 여부 확인)

os 사용

import os

filepath = "example.txt"
if os.path.exists(filepath):
    print("파일 존재함")
  • 문자열 경로 처리

pathlib.Path 사용

from pathlib import Path

filepath = Path("example.txt")
if filepath.exists():
    print("파일 존재함")
  • Path 객체 사용 → 경로 조작이 직관적이고 가독성 향상

6. array

메모리 효율적인 배열 사용.

메모리 절약, 인덱스 접근 속도 향상 등의 장점도 있지만 데이터 타입을 고정해야 하므로, 서로 다른 데이터 타입을 저장할 수 있는 리스트보다 유연성이 떨어진다.

6.1 array.array

리스트 사용 (비효율적)

lst = [1, 2, 3, 4, 5]  # 객체 포인터 저장
  • 객체 포인터 저장 → 메모리 사용량 증가

array 사용 (효율적)

from array import array

arr = array('i', [1, 2, 3, 4, 5])  # 'i'는 정수(int) 타입 지정
  • 연속된 메모리 블록 사용 → 메모리 절약, 성능 향상

7. 병렬 처리

7.1 multiprocessing (CPU 병렬 처리)

단일 프로세스 실행 (느림)

def work(n):
    return sum(i*i for i in range(n))

nums = [10**6, 10**6, 10**6, 10**6]
results = [work(n) for n in nums]  # 한 개씩 실행 (느림)
  • 한 번에 하나씩 처리 → CPU 코어 활용 부족

multiprocessing 사용 (빠름)

from multiprocessing import Pool

def work(n):
    return sum(i*i for i in range(n))

nums = [10**6, 10**6, 10**6, 10**6]
with Pool() as pool:
    results = pool.map(work, nums)  # 병렬 실행 (빠름)
  • 여러 코어에서 병렬 실행 → 실행 속도 향상

7.2 concurrent.futures.ThreadPoolExecutor (I/O 최적화)

단일 스레드 실행 (느림)

import requests

urls = ["https://example.com"] * 10

for url in urls:
    response = requests.get(url)
    print(response.status_code)
  • 한 번에 하나씩 처리 → I/O 작업에 시간이 많이 소요됨

ThreadPoolExecutor 사용 (빠름)

from concurrent.futures import ThreadPoolExecutor
import requests

urls = ["https://example.com"] * 10

with ThreadPoolExecutor() as executor:
    results = executor.map(requests.get, urls)

for response in results:
    print(response.status_code)
  • 여러 스레드에서 병렬 실행 → I/O 대기 시간 동안 다른 요청 처리 가능, 속도 향상