Skip to content

Python F-Strings: 문자열 포맷팅 완벽 가이드

Updated on

문자열 포맷팅은 Python에서 가장 흔한 연산 중 하나이지만, 수년 동안 좌절의 원인이었습니다. % 연산자는 C에서 유래한 난해한 형식 코드를 사용합니다. .format() 메서드는 값을 템플릿에서 실제로 나타나는 위치에서 멀리 떨어뜨려 놓습니다. +를 사용한 문자열 연결은 수동으로 타입을 변환해야 하고 지저분하며 읽기 어려운 코드를 생산합니다. 모든 접근 방식은 값을 문자열 안에 넣는 단순한 작업에 마찰을 더하는 것처럼 느껴집니다.

실제 프로젝트에서는 문제가 더 심각해집니다. 통화를 소수점 둘째 자리까지 포맷팅하고, 보고서에서 열을 정렬하고, 선행 영으로 숫자를 패딩하고, 백분율을 표시하며, 타임스탬프를 포맷팅해야 하는데, 동시에 코드의 가독성을 유지해야 합니다. 이전 포맷팅 방법을 사용하면 템플릿 문자열과 인자 목록이라는 두 개의 병렬 구조를 유지 관리하게 됩니다. 단순히 순서를 재배열하는 실수 하나가 모든 것을 조용히 망가뜨려 오류 대신 잘못된 출력을 생성합니다.

Python 3.6은 f-strings(형식화 문자열 리터럴, formatted string literals)를 도입했고, 이는 문자열 포맷팅을 영구적으로 바꾸었습니다. 문자열에 f 접두사를 붙이고 {중괄호} 안에 표현식을 직접 내장함으로써, f-strings는 값이 나타나는 위치 바로 옆에 값을 유지합니다. 이들은 다른 모든 포맷팅 방법보다 빠릅니다. 전체 범위의 형식 지정을 지원합니다. 그리고 Python 3.8에서는 = 지정자를 통해 내장 디버깅 기능을 얻었습니다. 이 가이드는 실행 가능한 실용적인 예제와 함께 모든 f-string 기능을 다룹니다.

📚

F-Strings란 무엇인가?

F-strings, 정식 명칭은 "형식화 문자열 리터럴(formatted string literals)"로, PEP 498 (opens in a new tab)에서 제안되었고 Python 3.6과 함께 출시되었습니다. 개념은 간단합니다: 문자열에 f(또는 F) 접두사를 붙이면, Python은 중괄호 {} 안의 모든 표현식을 런타임에 평가하여 결과를 문자열로 변환하고 출력에 삽입합니다.

name = "Alice"
age = 30
 
greeting = f"My name is {name} and I am {age} years old."
print(greeting)
# Output: My name is Alice and I am 30 years old.

f 접두사는 작은따옴표, 큰따옴표, 삼중 따옴표 모두와 함께 작동합니다:

single = f'Hello, {name}'
double = f"Hello, {name}"
triple_double = f"""Hello, {name}"""
triple_single = f'''Hello, {name}'''

내부적으로 Python은 f-strings를 파싱 시점에 일련의 문자열 연결과 format() 연산으로 컴파일합니다. 이것이 f-strings가 직접 .format()을 호출하는 것보다 빠른 이유입니다 -- 인터프리터가 연산을 직접 최적화하기 때문입니다.

기본 F-String 문법

핵심 문법은 간단합니다: f"텍스트 {표현식} 추가 텍스트"처럼 작성하세요. Python은 표현식을 평가하고 결과에 str()을 호출하여 문자열에 삽입합니다.

# Variables
city = "Tokyo"
population = 13960000
 
print(f"{city} has a population of {population}.")
# Output: Tokyo has a population of 13960000.
 
# You can use either f or F
print(F"Welcome to {city}!")
# Output: Welcome to Tokyo!

단일 f-string 안에 원하는 만큼의 표현식을 배치할 수 있습니다:

first = "Grace"
last = "Hopper"
title = "Rear Admiral"
year = 1906
 
bio = f"{title} {first} {last}, born {year}, lived to {1992 - year} years."
print(bio)
# Output: Rear Admiral Grace Hopper, born 1906, lived to 86 years.

F-String 내부의 표현식

F-strings는 단순히 변수를 삽입하는 것이 아닙니다. 중괄호 사이의 유효한 Python 표현식을 평가합니다. 여기에는 산술, 메서드 호출, 함수 호출, 삼항 표현식, 리스트 인덱싱, 딕셔너리 접근 등이 포함됩니다.

산술 및 수학

x = 15
y = 4
 
print(f"{x} + {y} = {x + y}")
print(f"{x} / {y} = {x / y:.2f}")
print(f"{x} ** {y} = {x ** y}")
print(f"{x} % {y} = {x % y}")
# Output:
# 15 + 4 = 19
# 15 / 4 = 3.75
# 15 ** 4 = 50625
# 15 % 4 = 3

메서드 호출

text = "  hello, python world  "
 
print(f"Stripped: '{text.strip()}'")
print(f"Title case: '{text.strip().title()}'")
print(f"Upper: '{text.strip().upper()}'")
print(f"Replace: '{text.strip().replace('python', 'f-string')}'")
# Output:
# Stripped: 'hello, python world'
# Title case: 'Hello, Python World'
# Upper: 'HELLO, PYTHON WORLD'
# Replace: 'hello, f-string world'

함수 호출

def calculate_bmi(weight_kg, height_m):
    return weight_kg / (height_m ** 2)
 
weight = 70
height = 1.75
 
print(f"BMI: {calculate_bmi(weight, height):.1f}")
# Output: BMI: 22.9
 
# Built-in functions
items = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Items: {items}")
print(f"Count: {len(items)}, Sum: {sum(items)}, Min: {min(items)}, Max: {max(items)}")
# Output:
# Items: [3, 1, 4, 1, 5, 9, 2, 6]
# Count: 8, Sum: 31, Min: 1, Max: 9

삼항(조건부) 표현식

score = 85
status = f"Result: {'PASS' if score >= 60 else 'FAIL'}"
print(status)
# Output: Result: PASS
 
temperature = -5
print(f"Water is {'frozen' if temperature <= 0 else 'liquid' if temperature < 100 else 'steam'}.")
# Output: Water is frozen.

딕셔너리 및 리스트 접근

user = {"name": "Bob", "role": "engineer", "level": 3}
scores = [88, 92, 76, 95, 81]
 
print(f"{user['name']} is a level {user['level']} {user['role']}.")
# Output: Bob is a level 3 engineer.
 
print(f"First score: {scores[0]}, Last score: {scores[-1]}")
# Output: First score: 88, Last score: 81

형식 지정: 숫자, 정렬 및 패딩

F-strings의 진정한 힘은 형식 지정 사양(format specifications)에서 나타납니다. 표현식 뒤에 콜론 :을 추가하고 그 뒤에 형식 사양을 붙이세요. 일반적인 문법은 다음과 같습니다:

{표현식:[[fill]align][sign][#][0][width][grouping_option][.precision][type]}

이것은 복잡해 보이지만, 각 부분은 선택 사항입니다. 예제를 통해 하나씩 살펴보겠습니다.

소수점 및 부동소수점 정밀도

.Nf 지정자는 부동소수점 수가 표시되는 소수점 자릿수를 제어합니다:

pi = 3.141592653589793
 
print(f"Default:    {pi}")
print(f"2 decimals: {pi:.2f}")
print(f"4 decimals: {pi:.4f}")
print(f"0 decimals: {pi:.0f}")
print(f"8 decimals: {pi:.8f}")
# Output:
# Default:    3.141592653589793
# 2 decimals: 3.14
# 4 decimals: 3.1416
# 0 decimals: 3
# 8 decimals: 3.14159265

천 단위 구분 기호

큰 숫자를 쉼표나 밑줄 그룹화로 즉시 읽기 쉽게 만들 수 있습니다:

revenue = 1234567890
small_amount = 1234.5
 
print(f"Revenue: {revenue:,}")
print(f"Revenue: {revenue:_}")
print(f"Amount: ${small_amount:,.2f}")
# Output:
# Revenue: 1,234,567,890
# Revenue: 1_234_567_890
# Amount: $1,234.50

백분율 포맷팅

% 타입은 값을 100배 곱하고 백분율 기호를 붙입니다:

completion = 0.876
error_rate = 0.034
growth = 1.25
 
print(f"Completion: {completion:.1%}")
print(f"Error rate: {error_rate:.2%}")
print(f"Growth: {growth:.0%}")
# Output:
# Completion: 87.6%
# Error rate: 3.40%
# Growth: 125%

과학적 표기법

avogadro = 6.022e23
planck = 6.626e-34
 
print(f"Avogadro: {avogadro:.3e}")
print(f"Planck: {planck:.4E}")
# Output:
# Avogadro: 6.022e+23
# Planck: 6.6260E-34

정수 진법: 이진수, 팔진수, 십육진수

value = 255
 
print(f"Decimal:     {value:d}")
print(f"Binary:      {value:b}")
print(f"Octal:       {value:o}")
print(f"Hex (lower): {value:x}")
print(f"Hex (upper): {value:X}")
print(f"With prefix: {value:#b}  {value:#o}  {value:#x}")
# Output:
# Decimal:     255
# Binary:      11111111
# Octal:       377
# Hex (lower): ff
# Hex (upper): FF
# With prefix: 0b11111111  0o377  0xff

정렬 및 패딩

정렬 지정자는 주어진 너비 내에서 값이 어떻게 위치하는지 제어합니다. 왼쪽 정렬에는 <, 오른쪽 정렬에는 >, 가운데 정렬에는 ^를 사용하세요:

label = "Python"
 
print(f"|{label:<20}|")   # Left-align in 20 chars
print(f"|{label:>20}|")   # Right-align
print(f"|{label:^20}|")   # Center
print(f"|{label:*^20}|")  # Center with * fill
print(f"|{label:->20}|")  # Right with - fill
# Output:
# |Python              |
# |              Python|
# |       Python       |
# |*******Python*******|
# |--------------Python|

숫자에 대한 영 패딩(zero-padding)은 보고서 포맷팅에서 흔합니다:

for i in [1, 42, 100, 7, 999]:
    print(f"ID: {i:05d}")
# Output:
# ID: 00001
# ID: 00042
# ID: 00100
# ID: 00007
# ID: 00999

정렬된 테이블 구축

정렬과 형식 사양을 결합하면 깔끔한 테이블을 생성할 수 있습니다:

products = [
    ("Laptop Pro", 1299.99, 45),
    ("Wireless Mouse", 29.50, 230),
    ("USB-C Hub", 54.95, 120),
    ("Monitor 27in", 449.00, 67),
]
 
print(f"{'Product':<18} {'Price':>10} {'Stock':>7}")
print("-" * 37)
for name, price, stock in products:
    print(f"{name:<18} ${price:>9.2f} {stock:>7,}")
print("-" * 37)
 
total_value = sum(p * s for _, p, s in products)
print(f"{'Total Value':<18} ${total_value:>9,.2f}")
 
# Output:
# Product               Price   Stock
# -------------------------------------
# Laptop Pro         $ 1,299.99      45
# Wireless Mouse     $    29.50     230
# USB-C Hub          $    54.95     120
# Monitor 27in       $   449.00      67
# -------------------------------------
# Total Value        $91,498.05

F-String을 활용한 날짜 및 시간 포맷팅

F-strings는 strftime 형식 코드를 직접 받아들이므로, .strftime()를 호출하지 않고도 datetime 객체를 포맷팅할 수 있습니다:

from datetime import datetime, date, timedelta
 
now = datetime.now()
 
print(f"ISO format:  {now:%Y-%m-%d %H:%M:%S}")
print(f"US format:   {now:%m/%d/%Y}")
print(f"Long format: {now:%B %d, %Y at %I:%M %p}")
print(f"Day of week: {now:%A}")
print(f"Short month: {now:%b %d}")
# Output (varies by current time):
# ISO format:  2026-02-13 14:30:00
# US format:   02/13/2026
# Long format: February 13, 2026 at 02:30 PM
# Day of week: Friday
# Short month: Feb 13

이것은 date 객체에서도 작동합니다:

from datetime import date
 
birthday = date(1995, 8, 15)
today = date.today()
age_days = (today - birthday).days
 
print(f"Birthday: {birthday:%B %d, %Y}")
print(f"Days alive: {age_days:,}")
print(f"Years (approx): {age_days / 365.25:.1f}")
# Output:
# Birthday: August 15, 1995
# Days alive: 11,139
# Years (approx): 30.5

멀티라인 F-Strings

삼중 따옴표 f-strings를 사용하면 형식화된 텍스트 블록을 구축할 수 있습니다. 삼중 따옴표 f-strings의 모든 줄은 {} 표현식을 포함할 수 있습니다:

project = "Data Pipeline"
owner = "Engineering Team"
status = "In Progress"
completion = 0.73
budget = 250000
spent = 182500
 
report = f"""
========================================
  Project Status Report
========================================
  Project:    {project}
  Owner:      {owner}
  Status:     {status}
  Completion: {completion:.0%}
  Budget:     ${budget:>12,}
  Spent:      ${spent:>12,}
  Remaining:  ${budget - spent:>12,}
========================================
"""
 
print(report)

또한 암시적 문자열 연결(연산자 없이 서로 옆에 배치)을 사용하여 여러 f-strings를 연결함으로써 멀티라인 f-strings를 구축할 수도 있습니다:

name = "Alice"
role = "Data Scientist"
years = 5
 
bio = (
    f"Name: {name}\n"
    f"Role: {role}\n"
    f"Experience: {years} years\n"
    f"Seniority: {'Senior' if years >= 5 else 'Mid-level'}"
)
 
print(bio)
# Output:
# Name: Alice
# Role: Data Scientist
# Experience: 5 years
# Seniority: Senior

두 번째 접근 방식은 삼중 따옴표 문자열과 함께 때때로 발생하는 선행 개행 및 들여쓰기 문제를 피합니다.

디버깅을 위한 = 지정자 (Python 3.8+)

Python 3.8은 f-strings에 = 지정자를 추가했고, 이는 언어에서 가장 유용한 디버깅 기능 중 하나입니다. f"{expression=}"라고 작성하면 Python은 표현식 텍스트와 그 값을 모두 출력합니다.

x = 42
y = 17
 
print(f"{x=}")
print(f"{y=}")
print(f"{x + y=}")
print(f"{x * y=}")
# Output:
# x=42
# y=17
# x + y=59
# x * y=714

=는 형식 지정자와 결합할 수 있습니다:

price = 49.99
tax_rate = 0.0825
total = price * (1 + tax_rate)
 
print(f"{price=:.2f}")
print(f"{tax_rate=:.1%}")
print(f"{total=:.2f}")
# Output:
# price=49.99
# tax_rate=8.2%
# total=54.12

= 지정자는 주변의 공백을 보존합니다. = 앞에 공백을 추가하면 출력이 형식화됩니다:

name = "Alice"
score = 95
 
print(f"{name = }")
print(f"{score = }")
# Output:
# name = 'Alice'
# score = 95

문자열의 경우 =는 기본적으로 repr()을 사용합니다(따옴표 표시). 숫자의 경우 str()을 사용합니다.

복잡한 표현식 디버깅

= 지정자는 모든 표현식에서 작동하여 중간 값을 검사하는 빠른 방법을 제공합니다:

data = [23, 45, 12, 67, 34, 89, 56]
 
print(f"{len(data)=}")
print(f"{sum(data)=}")
print(f"{sum(data)/len(data)=:.2f}")
print(f"{sorted(data)=}")
print(f"{max(data) - min(data)=}")
# Output:
# len(data)=7
# sum(data)=326
# sum(data)/len(data)=46.57
# sorted(data)=[12, 23, 34, 45, 56, 67, 89]
# max(data) - min(data)=77

Jupyter 노트북에서 작업하면서 디버깅을 위해 끊임없이 print(f"{variable=}") 호출을 추가하고 있다면, Jupyter 내부에서 직접 실행되는 AI 에이전트인 RunCell (opens in a new tab)을 고려해 보세요. RunCell은 노트북 메모리의 변수를 이해하고 디버그 문을 수동으로 작성하지 않고도 검사하고 설명하며 수정 사항을 제안할 수 있습니다. 여러 셀에 걸쳐 중간 값을 검증해야 하는 데이터 변환을 단계별로 진행할 때 특히 유용합니다.

중첩 F-Strings

F-strings 안에 f-strings를 중첩할 수 있습니다. 가장 흔한 사용 사례는 동적 형식 사양입니다. 여기서 너비나 정밀도가 변수에서 옵니다:

# Dynamic precision
value = 3.14159265
for precision in range(1, 6):
    print(f"  {precision} decimals: {value:.{precision}f}")
# Output:
#   1 decimals: 3.1
#   2 decimals: 3.14
#   3 decimals: 3.142
#   4 decimals: 3.1416
#   5 decimals: 3.14159
# Dynamic width
header = "Report"
for width in [20, 30, 40]:
    print(f"|{header:^{width}}|")
# Output:
# |       Report       |
# |            Report            |
# |                 Report                 |
# Nested f-string for formatting a list
values = [1.234, 56.789, 0.001, 999.999]
decimals = 2
formatted = f"Results: {', '.join(f'{v:.{decimals}f}' for v in values)}"
print(formatted)
# Output: Results: 1.23, 56.79, 0.00, 1000.00

중첩은 절제해서 사용하세요. f-strings가 두 단계 이상의 중첩을 필요로 한다면, 내부 로직을 변수나 함수로 추출하여 가독성을 높이세요.

F-Strings vs 다른 문자열 포맷팅 방법

Python에는 문자열 포맷팅을 위한 네 가지 주요 접근 방식이 있습니다. 직접적인 비교는 다음과 같습니다:

기능f-string f"...{x}...".format() "...{}...".format(x)% 연산자 "...%s..." % xTemplate Template("...$x...")
Python 버전3.6+2.6+AllAll
가독성우수 -- 값이 인라인좋음 -- 번호/이름 있는 자리 표시자보통 -- 위치 코드좋음 -- 이름 있는 자리 표시자
성능가장 빠름~1.5-2배 느림~1.3-1.8배 느림가장 느림
임의 표현식제한적아니오아니오
디버그 지정자 (=)예 (3.8+)아니오아니오아니오
재사용 가능한 템플릿아니오
사용자 입력에 안전아니오아니오아니오예 (safe_substitute)
타입 포맷팅전체전체부분없음
name = "Charlie"
balance = 1234.56
 
# f-string (recommended)
print(f"{name} has ${balance:,.2f}")
 
# .format()
print("{} has ${:,.2f}".format(name, balance))
 
# % formatting
print("%s has $%,.2f" % (name, balance))  # Note: %  does not support comma grouping
 
# Template (from string module)
from string import Template
t = Template("$name has $balance")
print(t.substitute(name=name, balance=f"${balance:,.2f}"))

각각을 사용하는 경우:

  • F-strings: Python 3.6+를 실행할 때마다 새 코드의 기본 선택.
  • .format(): 변수나 구성 파일에 저장된 재사용 가능한 템플릿이 필요할 때 사용.
  • % 포맷팅: 레거시 코드 전용. 새 프로젝트에서 사용할 이유가 없음.
  • Template: 형식 문자열이 신뢰할 수 없는 사용자 입력에서 올 때 사용(임의 표현식을 실행할 수 없음).

성능 비교

F-strings는 파싱 시점에 최적화된 바이트코드로 컴파일되어 .format()%에 필요한 메서드 호출 및 인자 파싱 오버헤드를 피하기 때문에 더 빠릅니다.

import timeit
 
name = "Alice"
age = 30
score = 95.5
 
# Benchmark each method with 1 million iterations
fstring_time = timeit.timeit(
    'f"{name} scored {score:.1f} at age {age}"',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
format_time = timeit.timeit(
    '"{} scored {:.1f} at age {}".format(name, score, age)',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
percent_time = timeit.timeit(
    '"%s scored %.1f at age %d" % (name, score, age)',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
concat_time = timeit.timeit(
    'name + " scored " + str(score) + " at age " + str(age)',
    globals={"name": name, "age": age, "score": score},
    number=1_000_000
)
 
print(f"f-string:      {fstring_time:.4f}s (baseline)")
print(f"str.format():  {format_time:.4f}s ({format_time/fstring_time:.2f}x slower)")
print(f"% formatting:  {percent_time:.4f}s ({percent_time/fstring_time:.2f}x slower)")
print(f"concatenation: {concat_time:.4f}s ({concat_time/fstring_time:.2f}x slower)")
 
# Typical results:
# f-string:      0.0850s (baseline)
# str.format():  0.1450s (1.71x slower)
# % formatting:  0.1100s (1.29x slower)
# concatenation: 0.1200s (1.41x slower)

성능 격차는 표현식이 더 복잡해질수록 커집니다. 수천 개의 레코드를 처리하는 타이트한 루프에서 f-strings는 측정 가능한 차이를 만듭니다.

흔한 실수와 주의사항

중괄호 이스케이프

F-string에 리터럴 { 또는 }를 포함하려면 두 배로 하세요:

value = 42
 
# Literal braces around a value
print(f"{{{value}}}")
# Output: {42}
 
# JSON-like output
key = "name"
val = "Alice"
print(f'{{"{key}": "{val}"}}')
# Output: {"name": "Alice"}
 
# Just literal braces, no interpolation
print(f"Use {{variable}} syntax in f-strings")
# Output: Use {variable} syntax in f-strings

표현식 내부의 백슬래시

F-string의 {} 표현식 부분에는 백슬래시 문자를 사용할 수 없습니다. 이는 가독성을 위한 의도적인 설계 선택입니다:

items = ["apple", "banana", "cherry"]
 
# This causes a SyntaxError:
# print(f"{'\\n'.join(items)}")
 
# Solution 1: assign to a variable first
newline = "\n"
print(f"{newline.join(items)}")
 
# Solution 2: use a separate operation
joined = "\n".join(items)
print(f"Items:\n{joined}")
 
# Solution 3: use chr()
print(f"{chr(10).join(items)}")

따옴표 충돌

F-string이 큰따옴표를 사용할 때, 내부의 표현식은 작은따옴표를 사용해야 합니다(또는 그 반대):

data = {"name": "Alice", "age": 30}
 
# Use single quotes inside when f-string uses double quotes
print(f"Name: {data['name']}, Age: {data['age']}")
 
# Or use double quotes inside when f-string uses single quotes
print(f'Name: {data["name"]}, Age: {data["age"]}')
 
# With triple quotes, you have more flexibility
print(f"""Name: {data["name"]}, Age: {data["age"]}""")

F-Strings는 상수가 아닙니다

F-strings는 런타임에 평가되므로, 런타임 상태에 의존하는 기본 인자 값이나 모듈 수준 상수로 사용할 수 없습니다:

# This works but evaluates at call time, not definition time
def greet(name, template=None):
    if template is None:
        template = f"Hello, {name}!"  # Evaluated here
    return template
 
# For true templates, use str.format()
TEMPLATE = "Hello, {name}! You have {count} messages."
print(TEMPLATE.format(name="Alice", count=5))

큰 표현식 조심하기

F-string 안에 어떤 표현식이든 넣을 수 있다고 해서 그래야 하는 것은 아닙니다. F-string 표현식을 단순하게 유지하세요:

# Hard to read -- too much logic inside the f-string
result = f"{'%.2f' % (sum(x**2 for x in range(100)) / 100)}"
 
# Much better -- compute first, then format
mean_square = sum(x**2 for x in range(100)) / 100
result = f"{mean_square:.2f}"

Raw F-Strings

r(raw)와 f 접두사를 결합하면 백슬래시가 문자 그대로 처리되는(이스케이프 시퀀스 없음) raw f-string을 생성하면서도 표현식은 여전히 평가됩니다:

user = "admin"
folder = "projects"
 
# Raw f-string for Windows paths
path = rf"C:\Users\{user}\{folder}\data.csv"
print(path)
# Output: C:\Users\admin\projects\data.csv
 
# Useful for regex patterns with dynamic parts
import re
prefix = "user"
pattern = rf"\b{prefix}_\d+\b"
text = "Found user_123 and user_456 in the log"
matches = re.findall(pattern, text)
print(f"Matches: {matches}")
# Output: Matches: ['user_123', 'user_456']

rf"..."fr"..." 모두 유효합니다 -- 접두사의 순서는 중요하지 않습니다.

데이터 사이언스 워크플로우에서의 F-Strings

F-strings는 출력 포맷팅, 동적 레이블 구축, 숫자 결과에서 읽기 쉬운 요약 생성을 위해 데이터 사이언스에서 매우 valuable합니다.

숫자 출력 포맷팅

import statistics
 
data = [23.4, 45.1, 31.8, 52.3, 41.7, 38.9, 29.6, 47.2]
 
mean = statistics.mean(data)
median = statistics.median(data)
stdev = statistics.stdev(data)
cv = stdev / mean  # coefficient of variation
 
print(f"Sample size:    {len(data)}")
print(f"Mean:           {mean:.2f}")
print(f"Median:         {median:.2f}")
print(f"Std deviation:  {stdev:.2f}")
print(f"CV:             {cv:.1%}")
print(f"Range:          {min(data):.1f} - {max(data):.1f}")
# Output:
# Sample size:    8
# Mean:           38.75
# Median:         40.30
# Std deviation:  9.87
# CV:             25.5%
# Range:          23.4 - 52.3

Pandas DataFrame과 함께 사용하기

import pandas as pd
 
df = pd.DataFrame({
    "product": ["Widget A", "Widget B", "Widget C", "Widget D"],
    "revenue": [125000, 89000, 234000, 67000],
    "units": [1250, 2100, 980, 3400],
})
 
# Summary statistics with f-strings
total_rev = df["revenue"].sum()
avg_price = (df["revenue"] / df["units"]).mean()
 
print(f"Total Revenue:  ${total_rev:>12,}")
print(f"Avg Unit Price: ${avg_price:>12,.2f}")
print(f"Products:       {len(df):>12,}")
 
# Dynamic column formatting
for _, row in df.iterrows():
    unit_price = row["revenue"] / row["units"]
    print(f"  {row['product']:<12} | Revenue: ${row['revenue']:>9,} | Units: {row['units']:>5,} | $/unit: ${unit_price:.2f}")
 
# Output:
# Total Revenue:  $     515,000
# Avg Unit Price: $       56.00
# Products:              4
#   Widget A     | Revenue: $  125,000 | Units: 1,250 | $/unit: $100.00
#   Widget B     | Revenue: $   89,000 | Units: 2,100 | $/unit: $42.38
#   Widget C     | Revenue: $  234,000 | Units:   980 | $/unit: $238.78
#   Widget D     | Revenue: $   67,000 | Units: 3,400 | $/unit: $19.71

텍스트 요약을 넘어서서 대화형 탐색이 필요할 때, PyGWalker (opens in a new tab)는 모든 pandas DataFrame을 단 한 줄의 코드로 Tableau와 같은 대화형 시각화로 변환할 수 있습니다. 정적 보고서를 위해 숫자를 수동으로 포맷팅하는 대신, 열을 드래그 앤 드롭하여 차트를 구축하고, 필터를 적용하며, 시각적으로 패턴을 탐색할 수 있습니다 -- 모두 Jupyter 노트북 내부에서.

import pandas as pd
import pygwalker as pyg
 
# After preparing your DataFrame with well-formatted columns
df = pd.DataFrame({
    "Month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
    "Revenue": [125000, 134000, 158000, 142000, 167000, 189000],
    "Growth": [0.05, 0.072, 0.179, -0.101, 0.176, 0.132],
})
 
# Add formatted columns for display
df["Revenue_Display"] = df["Revenue"].apply(lambda x: f"${x:,.0f}")
df["Growth_Display"] = df["Growth"].apply(lambda x: f"{x:+.1%}")
 
# Launch interactive visualization
# pyg.walk(df)

모델 결과 포맷팅

# Formatting machine learning results
metrics = {
    "accuracy": 0.9234,
    "precision": 0.8891,
    "recall": 0.9456,
    "f1_score": 0.9164,
    "auc_roc": 0.9678,
}
 
print("Model Evaluation Results")
print("=" * 35)
for metric, value in metrics.items():
    bar_length = int(value * 20)
    bar = "#" * bar_length + "-" * (20 - bar_length)
    print(f"  {metric:<12} {value:.4f}  [{bar}]")
# Output:
# Model Evaluation Results
# ===================================
#   accuracy     0.9234  [##################--]
#   precision    0.8891  [#################---]
#   recall       0.9456  [##################--]
#   f1_score     0.9164  [##################--]
#   auc_roc      0.9678  [###################-]

변환 플래그: !s, !r, 그리고 !a

F-strings는 표현식 값이 포맷팅되기 전에 변환되는 방식을 제어하는 세 가지 변환 플래그를 지원합니다:

  • !s는 값에 str()을 호출합니다(기본 동작)
  • !r은 값에 repr()을 호출합니다
  • !a는 값에 ascii()를 호출합니다
text = "Hello\tWorld"
name = "Caf\u00e9"
 
print(f"str:   {text!s}")
print(f"repr:  {text!r}")
print(f"ascii: {name!a}")
# Output:
# str:   Hello	World
# repr:  'Hello\tWorld'
# ascii: 'Caf\xe9'

!r 플래그는 디버깅에 특히 유용합니다. 왜냐하면 따옴표와 이스케이프 문자를 포함한 원시 표현을 보여주기 때문입니다. = 지정자와 함께 잘 작동합니다.

자주 묻는 질문

Python f-strings란 무엇이며 언제 도입되었나요?

F-strings(형식화 문자열 리터럴)는 PEP 498을 통해 Python 3.6에서 도입된 문자열 포맷팅 메커니즘입니다. 문자열에 f 접두사를 붙이고 중괄호 안에 표현식을 배치함으로써 Python 표현식을 문자열 리터럴 내부에 직접 내장할 수 있게 해줍니다. F-strings는 런타임에 평가되며, 모든 포맷팅 옵션 중 최고의 가독성을 제공하고, 파싱 시점에 최적화된 바이트코드로 컴파일되므로 str.format()% 포맷팅보다 빠릅니다.

F-strings에서 숫자를 쉼표와 소수점으로 포맷팅하려면 어떻게 하나요?

중괄호 내부에서 콜론 뒤에 형식 사양을 사용하세요. 천 단위 구분 기호로 쉼표를 사용하려면 :,를 사용하세요 -- 예: f"{1234567:,}""1,234,567"을 생성합니다. 소수점 자릿수는 :Nf를 사용하며, 여기서 N은 자릿수입니다 -- 예: f"{3.14159:.2f}""3.14"를 줍니다. 둘을 결합하세요: f"{1234.5:,.2f}""1,234.50"을 출력합니다. 백분율의 경우 :.N%를 사용하는데, 이는 100을 곱하고 백분율 기호를 붙입니다: f"{0.85:.1%}""85.0%"를 생성합니다.

f-string = 지정자는 무엇이며 디버깅에 어떻게 도움이 되나요?

= 지정자는 Python 3.8에 추가되었고 표현식 텍스트와 그 값을 모두 출력합니다. f"{variable=}"을 작성하면 variable=value가 출력됩니다. 이는 디버깅 시 변수 이름을 두 번 입력할 필요를 없애줍니다. 모든 표현식에서 작동하며 f"{price=:.2f}"처럼 형식 사양과 결합할 수 있습니다.

멀티라인 문자열에서 f-strings를 사용할 수 있나요?

예. 멀티라인 f-strings에는 삼중 따옴표(f"""...""" 또는 f'''...''')를 사용하세요. 모든 줄은 {expression} 자리 표시자를 포함할 수 있습니다. 대안으로 괄호 안에 서로 옆에 배치하여 암시적 문자열 연결을 사용하여 여러 f-strings를 연결할 수도 있습니다.

f-strings가 str.format()과 % 포맷팅보다 빠른가요?

예. F-strings는 Python에서 일관되게 가장 빠른 문자열 포맷팅 방법입니다. 일반적으로 str.format()보다 1.52배 빠르며 % 포맷팅보다 1.31.8배 빠릅니다. 속도 이점은 Python이 f-strings를 런타임 메서드 조회 및 인자 파싱 없이 직접 효율적인 바이트코드로 변환하는 컴파일 타임 최적화에서 비롯됩니다.

F-string에 리터럴 중괄호를 포함하려면 어떻게 하나요?

중괄호를 두 배로 하세요. 리터럴 {에는 {{를, 리터럴 }에는 }}를 사용하세요. 예: f"{{value}}"는 일반 텍스트로 {value}를 출력합니다. 보간된 값을 중괄호로 감싸려면 f"{{{variable}}}"를 사용하세요 -- 바깥쪽 이중 중괄호는 리터럴 중괄호를 생성하고, 안쪽 단일 중괄호는 보간을 트리거합니다.

결론

F-strings는 현대 Python에서 문자열을 포맷팅하는 표준 방법입니다. 이들은 모든 포맷팅 접근 방식 중 최고의 가독성과 최고의 성능을 결합하며, 소수점 정밀도, 천 단위 구분 기호, 백분율, 과학적 표기법, 정렬, 패딩, 날짜 포맷팅, 진법 변환의 전체 범위를 지원합니다.

기억해야 할 핵심 사항:

  • f 접두사를 붙이고 {중괄호} 안에 표현식을 넣으세요.
  • 정밀한 출력 제어를 위해 : 뒤에 형식 사양을 사용하세요(:.2f, :, :.1%, :<20).
  • 디버깅을 위해 표현식 뒤에 =를 사용하세요(f"{variable=}"). Python 3.8+가 필요합니다.
  • 리터럴 중괄호는 두 배로 하세요: {{}}.
  • {} 표현식 내부에는 백슬래시를 넣지 마세요. 먼저 변수에 할당하세요.
  • 표현식을 단순하게 유지하세요. {} 내부의 로직이 읽기 어렵다면 추출하세요.
  • 변수에 저장된 재사용 가능한 템플릿이 필요할 때만 .format()을 사용하세요.

F-strings는 빠른 print() 디버깅부터 프로덕션 보고서 생성까지 모든 것을 처리합니다. 한번 채택하면 이전 포맷팅 방법으로 돌아갈 이유가 없습니다. 데이터 파이프라인 구축, ML 모델 출력 포맷팅, 또는 재무 보고서 생성에 관계없이, f-strings는 깔끔하고 빠르며 읽기 쉬운 코드를 제공합니다.

📚