본문으로 건너뛰기
개발 머꼬
개발 노트Python
hohyeon.dev32

문자열 포맷팅 방식이 여러 개인데 f-string이 대체로 더 빠른 이유

  • #Engineering Note
  • #Performance
  • #Python

문제 발생

오래된 코드베이스에 %-formatting, .format(), f-string이 뒤섞여 있어서 어떤 방식을 표준으로 삼아야 할지, 성능 차이가 실제로 있는지 확인이 필요했습니다.

name = "MEOKKO"
a = "Hello, %s" % name
b = "Hello, {}".format(name)
c = f"Hello, {name}"

원인 분석

세 방식은 결과가 같아도 내부 동작이 다릅니다.

  • %-formatting: C의 printf 스타일을 본뜬 가장 오래된 방식입니다. 위치 기반 치환만 지원하고, 튜플/딕셔너리 전달 규칙이 다소 번거로우며, 실수하기 쉬운 특수 케이스(예: 값이 튜플 하나일 때)가 있습니다.
  • .format(): %보다 유연하지만(이름 기반 치환, 정렬/포맷 지정자 등), 매번 메서드 호출을 통해 인자를 문자열 안의 자리에 매칭하는 처리 비용이 있습니다.
  • f-string(Python 3.6+): 컴파일 시점에 문자열 리터럴 안의 표현식이 실제 코드로 파싱되어, 런타임에는 표현식을 계산하고 이어붙이는 것과 비슷한 수준으로 처리됩니다 — 별도의 포맷 문자열 파싱 단계가 필요 없어 일반적으로 셋 중 가장 빠릅니다.

또한 f-string은 변수를 문자열 밖에 따로 나열할 필요 없이 표현식을 그 자리에 바로 쓸 수 있어 가독성도 좋습니다(f"{user.name.upper()}"처럼 메서드 호출도 바로 넣을 수 있습니다).

해결 방안

  1. 새로 작성하는 코드는 f-string을 기본으로 씁니다 — 성능과 가독성 양쪽에서 우세하고, Python 커뮤니티에서도 사실상 표준으로 자리 잡았습니다.
  2. 예외적으로 f-string을 쓸 수 없는 경우가 있습니다 — 포맷 문자열 자체가 런타임에 동적으로 결정되는 경우(예: 다국어 번역 문자열을 외부 파일에서 읽어와 나중에 값을 채우는 경우)는 f-string이 아니라 .format()을 씁니다. f-string은 파이썬 소스 코드 안에 리터럴로 존재해야만 동작합니다.
  3. 로깅 라이브러리(logging 모듈)에 메시지를 넘길 때는 f-string으로 미리 문자열을 완성하기보다, logger.info("user %s logged in", user_id)처럼 %-placeholder를 남겨두고 로거에 인자를 따로 넘기는 방식이 권장되기도 합니다 — 그 로그 레벨이 실제로 출력되지 않을 때는 문자열 포맷팅 자체를 건너뛰어 불필요한 비용을 아낄 수 있기 때문입니다(f-string은 로그 레벨과 무관하게 항상 즉시 평가됩니다).
  4. 성능 차이가 실제로 중요한 핫 패스라면, 추측하지 말고 timeit 모듈로 실제 코드에서 직접 측정해 판단합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.