
※ 내장 함수 vs 사용자 정의 함수
내장 함수(Built-in)는 파이썬이 기본 제공하는 함수로 즉시 사용 가능하며,
공통적인 작업(길이, 합, 최댓값 등)을 빠르게 처리합니다.
사용자 정의 함수(User-defined)는 문제에 맞는 로직을 def로 직접 정의해 재사용성과 가독성을 높입니다.
# 내장 함수 (Built-in)
print(len([1, 2, 3])) # 3
print(max(10, 20, 5)) # 20
print(sum([1, 2, 3])) # 6
# 사용자 정의 함수 (User-defined)
def add(a, b):
"두 수를 더한 값을 반환합니다." # 간단한 docstring
return a + b
print(add(3, 5)) # 8
→ 내장 함수는 공통 작업에 최적화되어 있고, 사용자 정의 함수는 문제 맞춤형 로직을 담습니다.
함수는 일급 객체(First-class)입니다. 즉, 변수에 대입/인자로 전달/리턴이 모두 가능합니다.
def hello(name):
return f"Hello, {name}"
greeter = hello # 함수 참조를 변수에 저장
print(greeter("Jiwoo")) # Hello, Jiwoo
def run_twice(f, x): # 함수를 인자로 받는 고차함수
return f(f(x))
def exclaim(s):
return s + "!"
print(run_twice(exclaim, "Hi")) # Hi!!
타입 힌트를 사용하면 인터페이스가 명확해지고, 에디터/CI에서 검증하기 쉬워집니다.
def mul(a: int, b: int) -> int:
return a * b
※ 매개변수, 기본값, 가변 매개변수
함수의 시그니처에는 위치 인자/키워드 인자/기본값/가변 인자 등 다양한 형태가 있습니다.
# (1) 위치 인자 & 기본값
def greet(name, msg="안녕하세요"):
print(f"{name}, {msg}")
greet("지우") # 지우, 안녕하세요
greet("지우", "반가워") # 지우, 반가워
# (2) 가변 인자 (*args): 개수 제한 없이 "값"들을 받음 (tuple)
def add_all(*args):
return sum(args)
print(add_all(1, 2, 3, 4)) # 10
# (3) 키워드 가변 인자 (**kwargs): 개수 제한 없이 "키=값"들을 받음 (dict)
def print_info(**kwargs):
for key, value in kwargs.items():
print(key, ":", value)
print_info(name="지우", age=26)
→ *args는 튜플, **kwargs는 딕셔너리로 전달됩니다.
→ 리스트/딕셔너리를 언패킹하여 인자로 전달할 수도 있습니다.
nums = [1, 2, 3]
print(add_all(*nums)) # 6 (리스트 언패킹)
profile = {"name": "지우", "msg": "Hi"}
greet(**profile) # 지우, Hi (딕셔너리 언패킹)
키워드 전용 매개변수(keyword-only)로 인터페이스를 명확히 할 수 있습니다.
def paginate(page: int, *, size: int = 10): # * 뒤는 반드시 키워드로만
print(f"page={page}, size={size}")
paginate(1, size=20) # OK
# paginate(1, 20) # TypeError (키워드 없이 size 전달 불가)
가변 객체를 기본값으로 쓰면 버그가 납니다. (호출 간 상태 공유) → None 패턴으로 방지하세요.
# 잘못된 예
def append_bad(item, bucket=[]):
bucket.append(item)
return bucket
print(append_bad(1)) # [1]
print(append_bad(2)) # [1, 2] ← 이전 호출의 상태가 남음 (버그)
# 올바른 예 (None 패턴)
def append_good(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(append_good(1)) # [1]
print(append_good(2)) # [2] ← 호출 간 독립적
호출 시 값 전달(객체 참조) 규칙: 불변 객체는 재대입만, 가변 객체는 내부 수정이 원본에 영향을 줄 수 있습니다.
def touch_scalar(x):
x = 999 # 지역 재대입 (원본 영향 없음)
def touch_list(li):
li[0] = 999 # 내부 수정 (원본 영향 있음)
a = 10
touch_scalar(a)
print(a) # 10 (불변)
b = [1, 2, 3]
touch_list(b)
print(b) # [999, 2, 3] (가변)
※ lambda / map, filter, reduce
lambda는 이름 없는 한 줄 함수입니다. 표현식만 가능(할당/반복문 불가)하므로,
복잡한 로직엔 def가 가독성이 더 좋습니다.
# lambda 기본
square = lambda x: x ** 2
print(square(5)) # 25
map은 모든 요소에 함수를 적용, filter는 조건을 만족하는 요소만, reduce는 누적 계산을 수행합니다.
nums = [1, 2, 3, 4]
# map: 각 요소에 2배
print(list(map(lambda x: x * 2, nums))) # [2, 4, 6, 8]
# filter: 짝수만
print(list(filter(lambda x: x % 2 == 0, nums))) # [2, 4]
# reduce: 누적 합
from functools import reduce
print(reduce(lambda x, y: x + y, nums)) # 10
→ 동일 작업을 리스트 컴프리헨션으로도 표현할 수 있습니다(가독성 선호).
# map 대체
print([x * 2 for x in nums]) # [2, 4, 6, 8]
# filter 대체
print([x for x in nums if x % 2 == 0]) # [2, 4]
→ sum, max처럼 내장 함수가 있는 경우 reduce보다 내장 함수를 우선 고려하세요.
※ 재귀 함수 (Recursive Function)
자기 자신을 호출하는 함수입니다. 기저 조건(Base case)이 없으면
무한 재귀로 이어지므로 반드시 종료 조건을 먼저 생각합니다.
# 팩토리얼 (재귀)
def factorial(n: int) -> int:
if n <= 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
→ 파이썬은 재귀 깊이에 제한이 있습니다(RecursionError). 깊은 재귀는 반복문/DP로 전환을 고려하세요.
※ Memoization (메모이제이션)
중복 계산 결과를 캐시에 저장해 다음 호출 시 바로 반환하는 기법입니다.
재귀 + 메모이제이션 = 동적 계획법(DP)의 핵심.
# 비효율적인 피보나치 (중복 호출 폭발)
def fib(n: int) -> int:
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(10)) # 55 (작은 n만 권장)
# 딕셔너리 캐시 사용
memo = {0: 0, 1: 1}
def fib_memo(n: int) -> int:
if n not in memo:
memo[n] = fib_memo(n - 1) + fib_memo(n - 2)
return memo[n]
print(fib_memo(50)) # 빠르고 안전하게 12586269025
→ @lru_cache로 캐시를 자동화할 수 있습니다.
from functools import lru_cache
@lru_cache(maxsize=None) # 무제한 캐시
def fib_cache(n: int) -> int:
if n <= 1:
return n
return fib_cache(n - 1) + fib_cache(n - 2)
print(fib_cache(100)) # 매우 빠르게 계산
'2025 현대오토에버 모빌리티 SW 스쿨(클라우드 2기) > 파이썬 이론' 카테고리의 다른 글
| [Python] 예외 처리와 디버깅 (0) | 2025.09.21 |
|---|---|
| [Python] 객체 지향 프로그래밍(OOP) (0) | 2025.09.21 |
| [Python] 연산자와 제어문 (0) | 2025.09.21 |
| [Python] 데이터 타입 완벽 정리 (2) – 고급 자료형 (0) | 2025.09.21 |
| [Python] 데이터 타입 완벽 정리 (1) – 기본 자료형 (0) | 2025.09.21 |