관련글 :
| functools 기반 데코레이터 상세설명 | https://waydd.tistory.com/58 |
1. 컴프리헨션 (Comprehension)
간결하고 직관적인 방식으로 반복 가능한 객체(iterable)를 기반으로 새로운 컬렉션을 만드는 문법
- for 루프 + 조건문 + 새로운 컬렉션 생성을 한 줄에 표현
→ A if 조건 else B 구조의 경우, 삼항 연산자(조건 표현식)이 되도록 함
→ for문 중첩도 가능 ex) 리스트 안의 리스트를 평탄화, 2중 반복할 때 사용 - 작은 데이터에서는 빠름 (C 구현 최적화)
- 재사용성 : 한번 생성 이후 여러번 반복 사용 가능
- 즉시 평가 (모든 원소를 메모리에 담아 생성)
(예시) 중간 리스트가 한 번 만들어진 후 복사됨 (원소 개수만큼 한번에 메모리 차지)
※ 조건 필터링과 if-else 표현식 차이점
① 필터용 if → 값은 고정, 조건만 검사 ex) [x for x in lst if x % 2 == 0]
② 조건표현식 if → 값도 조건 따라 달라짐 ex) [x if x % 2 == 0 else -x for x in lst]
- 리스트 컴프리헨션
- 기존 리스트를 기반 즉시 새로운 리스트를 생성 (빠르고 직관적)
- 먼저 전체 리스트를 메모리에 만든 뒤 컨테이너에 넣음 (즉시 완성된 리스트 반환)
- 순서 ⭕, 중복 허용
기본형 : [expression for variable in iterable[ if condition]]
확장형 : [expression_if_true if condition else expression_if_false for variable in iterable]
# 예시
[x**2 for x in range(5)] # → [0, 1, 4, 9, 16]
[x for x in range(10) if x % 2 == 0] # → [0, 2, 4, 6, 8]
- 셋(Set) 컴프리헨션
- 중복을 제거한 값을 기반으로 새로운 집합 생성
- 순서 ❌, 중복 제거
기본형 : {expression for variable in iterable[ if condition]}
# 예시
{len(word) for word in ["apple", "banana", "kiwi", "apple"]}
# → {4, 5, 6}
- 딕셔너리(Dictionary) 컴프리헨션
- 키와 값의 조건이나 연산을 적용해 새로운 딕셔너리 생성
- 키-값 쌍 생성, 중복 키 제거
기본형 : {key_expression: value_expression for variable in iterable[ if condition]}
# 예시
{word: len(word) for word in ["apple", "banana", "kiwi"]}
# → {'apple': 5, 'banana': 6, 'kiwi': 4}
2. 제너레이터
필요할 때마다 원소를 생성하는 객체 (리스트 아님)
중간 자료구조(materialization) 를 만들지 않고 iterable을 직접 순회 + 바로 대상 컨테이너에 요소를 채움 (바로 소비)
→ 메모리 효율이 약간 더 좋음
- 주로 컨테이너 생성자와 함께 사용
→ 원소를 하나씩 생성(lazy) 후, 컨테이너(list, tuple, set, deque, ...) 가 이걸 소비하면서 바로 채움
→ 중간 결과를 메모리에 담지 않음, 곧바로 컨테이너가 소비 - 재사용성 : 한 번만 소비 가능 (소진 후 다시 못 씀)
- 지연 평가(lazy evaluation) 이용 (필요할 때마다 원소를 하나씩 생성)
- yield 기반이라 큰 입력·스트리밍 처리에는 효율적, 전체를 다 모을 땐 리스트보다 느림
→ 단일 원소를 생성할 때만 메모리 사용
- iterable & iterator
- 제너레이터 : yield 또는 () 제너레이터 표현식으로 생성된 객체
- iterable: __iter__() 메서드를 가지며, for문 등에 사용 가능
- iterator: __next__() 메서드를 가지며, next() 호출 가능
- 즉, 제너레이터는 __iter__()와 __next__()를 모두 구현하므로 iterable이면서 iterator
※ Iterable (has __iter__ → returns self)
- list, tuple, dict, set, str, range, generator
- iterator
※ Iterator (has __next__) ⊂ Iterable
- generator
- iter(list), iter(str)
- 제너레이터 표현식 (generator expression)
- () 괄호를 사용하여 반복 가능한 객체(iterable)를 기반으로 변환/필터링된 결과인 반복자(iterator) 생성
- 직접 값을 생성하면서 next()로 꺼낼 수 있는(= 지연 평가) 이터레이터의 특수한 형태
→ generator는 한 번만 소비 가능한 iterator ≠ ex) list의 경우, 여러 번 반복 가능한 iterable - 리스트 컴프리핸션과 문법이 거의 동일, 컴프리헨션의 메모리 최적화 버전
기본형 : generator 객체(iterator) = (expression for variable in iterable[ if condition])
# 예시
g = (x * 2 for x in range(3))
print(next(g)) # 0
print(next(g)) # 2
- 제너레이터 함수(generator function)
- 마찬가지로 제너레이터 객체(iterator) 를 생성함
- 함수 정의 필요 (def, yield)
- 제너레이터 표현식보다 더 복잡한 로직 처리 가능 (조건문, 반복문, 예외처리, 로깅 등)
# 예시
def double():
for x in range(3):
yield x * 2
g = double()
print(next(g)) # 0
print(next(g)) # 2
# 주로 파일 읽기에 사용
def read_lines(file_path):
with open(file_path) as f:
for line in f:
yield line.strip() # 파일 한 줄씩
3. 함수형 스타일
함수형 프로그래밍 패러다임을 따르는 코딩 스타일
- 함수는 변하지 않고, 데이터만 변형됨 (= 데이터 흐름 위주 ≠ 기존 명령형 스타일은 절차 중심)
- 상태를 변경하지 않고 새 값을 반환함 (= 불변성)
→ 전역 변수 사용이나 print(), input()도 되도록 지양, 즉 사이드 이펙트를 줄임 - 코드의 명확성, 재사용성, 테스트 용이성을 높임
- 순수 함수와 다르게 함수를 인자로 받거나 함수를 반환하는 고차 함수 사용 ( 조건 / 변환 / 동기화 반복을 처리 )
→ 반복문 대신 map, filter, reduce, 리스트 컴프리헨션 사용
# 명령형 스타일 (조건 + 변환)
result = []
for x in nums:
if x > 0:
result.append(x * 2)
# 함수형 스타일
result = list(map(lambda x: x * 2, filter(lambda x: x > 0, nums)))
# 동기화 반복
for name, score in zip(names, scores):
print(f"{name}의 점수는 {score}")
- 대표적인 함수형 내장 함수
| 설명 | 예시 | |
| map | 각 요소에 함수 적용 | map(str, [1, 2, 3]) → '1','2','3' |
| filter | 조건을 만족하는 요소만 필터링 | filter(lambda x: x>0, lst) |
| reduce | 누적 계산 수행 (functools 필요) | reduce(lambda x,y: x+y, lst) |
| zip | 여러 iterable을 병렬 처리 | zip([1,2], ['a','b']) |
※ 함수형 친화적 유틸 함수
- lambda : 고차 함수, 익명 함수에서 활약
- enumerate : 순회와 인덱스 제공 (내부 상태를 직접 제어 X, 불변 데이터 반복 처리 간결)
4. 중첩 함수
함수 정의 안에 또 다른 함수를 정의하는 구조로, 내부 함수 혹은 로컬 함수라고도 부름
- 외부 함수에서 내부 함수를 반환하거나 호출 가능
- 외부에서 쓸이유가 없는 경우(캡슐화), 로직이 국지적인 경우(가독성)에 사용
- 함수가 너무 길고 복잡할 때나 재사용성이 높은 경우엔 X (따로 빼서 모듈화해야 유지보수 쉬움)
- 클로저와 데코레이터 등의 기반
# 중첩 함수
def outer():
def inner():
pass
- 클로저 (Closure)
- 중첩 함수의 일종
- 외부 함수의 지역 변수 값을 내부 함수가 기억하고 사용하는 함수 객체 (함수형 프로그래밍에서 자주 사용)
→ 중첩함수를 반환할때, 그 내부 함수가 외부 함수의 스코프에 있는 변수를 참조하면 클로저가 형성
# 클로저
def outer(x):
def inner(y):
return x + y
return inner
f = outer(10) ← 이 시점에서 inner 함수가 클로저가 됨
f(5) → 15
# x는 이미 outer 함수 실행이 끝났지만, inner()가 x의 값을 기억하고 있음 (= 상태 유지)
- 데코레이터
- 기존 함수를 수정하지 않고 감싸서 부가기능을 적용하는 함수 ( 중첩함수 + 클로저 )
- @ 기호를 이용해 간결하게 적용
# 데코레이터 정의
def deco(func):
def wrapper():
print("before")
func()
print("after")
return wrapper
# 데코레이터 적용 (= deco(hello)로 감쌈)
@deco
def hello():
print("hi")
# 함수 호출
hello() # before, hi, after 순으로 출력
※ @deco는 hello = deco(hello)와 동일
- deco 함수는 hello를 인자로 받아 wrapper를 반환, hello는 wrapper로 대체
→ hello()를 호출하면 실제로는 wrapper()가 실행됨
- 내부에서 정의한 wrapper()가 중첩함수, func를 기억하고 사용하므로 클로저
- 실행 시 before → hello() → after 순으로 출력됨
※ 데코레이터 종류
- @deco : 사용자 정의 데코레이터
- @staticmethod, @classmethod : 클래스 내 메서드 제어 (표준 내장)
- @property : 게터/세터 기능 구현 (표준 내장)
- @lru_cache : 결과를 캐시해서 속도 향상 (functools 기반)
- @wraps : 메타정보 유지 (functools 기반)
- @login_required : 권한 체크 (Flask, Django 웹 프레임워크에서 제공)
- @timer : 실행 시간 측정용 데코레이터 (직접 정의)
'Language & Tool > Python' 카테고리의 다른 글
| 🐍try-except부터 사용자 정의 예외까지(Python) (0) | 2025.06.15 |
|---|---|
| 🐍함수의 도구화, functools (0) | 2025.06.15 |
| 🌱리스트와 비슷한 튜플(tuple) (0) | 2025.06.11 |
| 🐍sort()와 sorted() 차이점 + 다른 정렬 방식 비교 (0) | 2025.06.11 |
| 🌱dict와 defaultdict + Counter (Python) (0) | 2025.06.10 |