C스타일 형식 문자열을 str.format과 쓰기보다는 f- 문자열을 통한 인터폴레이션을 사용하라

Minsang Yu·2023년 6월 3일
0

파이썬코드에서는 문자열을 많이 쓴다. 사용자 인터페이스 또는 명령중 유틸리티에 메시지를 표시하거나, 파일과 소켓에 데이터를 쓰거나, 어떤 일이 잘못됐는데 Exception에 자세히 기록할때 문자열을 사용한다.

형식화

미리 정의된 문자열에 데이터 값을 끼워 넣어서 사람이 보기 좋은 문자열로 저장하는 과정

파이썬은 언어의 내장된 4개의 밥법으로 형식화를 할 수 있다.

하지만 한가지 방법을 제외한 나머지 방법은 모두 심각한 단점이 있다.

  1. % 형식화 연산자
    이 연산자는 왼쪽에 들어가는 미리 정의된 텍스트 템플릿을 형식 문자열 이라고 부른다.
    # 읽기 어려운 2진값이나 16진값을 10진수로 표현
    a = 0b10111011
    b = 0xc5f
    print('2진수 : %d, 16진수 : %d' %(a, b))

형식 문자열은 연산자 왼쪽에 있는 값을 끼워 넣을 자리를 표현하기 위해 %d같은 형식 지정자를 사용 한다.

형식 지정자는 C언어의 printf에 사용할 수 있는 대부분의 형식 지정자를 지원하고, 소수점 위치나 패딩, 채워 넣기, 좌우 정렬 등도 제공한다.
프로그래머중 상당수는 익숙하고 사용하기 간편하다는 이유로 C 스타일 형식 문자열을 사용한다.

하지만 파이썬에서 C스타일 형식 문자열을 사용하는데는 네 가지 문제점이 있다.

  1. 형식화 식에서 오른쪽에 있는 tuple 내 데이터 값의 순서를 바꾸거나 값의 타입을 바꾸면 타입 변환이 불가능하므로 오류가 발생할 수 있다.
        key = 'my_var'
        value = 1.234
        formatted = '%-10s = %.2f' %(key, value)
        print(formatted)
        
        >>>
        my_var = 1.23

하지만 key와 vlaue의 위치를 바꾸면 실행 시점에 예외가 발생한다.

        key = 'my_var'
        value = 1.234
        formatted = '%-10s = %.2f' %(value, key) # value와 key의 순서가 바뀜 
        print(formatted)
        
        >>>
        exception occur ...

마찬가지로 오른쪽에 있는 파라미터의 순서를 그대로 유지하고 형식 문자열의 순서를 바꿔도 같은 오류가 발생한다.

이런 오류를 피하려면 % 연산자 좌우가 서로 잘 맞는지 계속 검사해야 한다. 코드를 변경하는 과정에서 개발자가 직접 검사해야 하므로 검사 과정에서 실수가 발생하기 쉽다.

  1. 형식화를 하기 전에 값을 살짝 변경 해야 한다면 식을 읽기가 매우 어려워진다.
        pantry = [
            ('아보카도', 1.25),
            ('바나나', 2),
            ('체리', 3.5),
        ]
        
        for i, (item, count) in enumerate(pantry):
            print('#%d: %-10s = %.2f' %(i, item, count))
        
        >>>
        #0: 아보카도       = 1.25
        #1: 바나나        = 2.00
        #2: 체리         = 3.50

값을 조금 바꿔서 출력된 메시지를 좀 더 쓸모있게 바꾸고 싶다. 이럴 경우 형식화 식에 있는 tuple의 길이가 너무 길어져 여러 줄에 나눠 써야 하는데, 그로 인해 가독성이 나빠진다.

        pantry = [
            ('아보카도', 1.25),
            ('바나나', 2),
            ('체리', 3.5),
        ]
        
        for i, (item, count) in enumerate(pantry):
            print('#%d: %-10s = %.2f' %(
                i+ 1 ,
                item.title(),
                round(count)
            ))
        >>>
        #1: 아보카도       = 1.00
        #2: 바나나        = 2.00
        #3: 체리         = 4.00
  1. 형식화 문자열에서 같은 값을 여러 번 사용하고 싶다면 튜플에서 같은 값을 여러 번 반복해야 한다.
    template = '%s는 음식을 좋아해. %s가 요리하는 모습을 봐요.'
    name = '철수'
    formatted = template %(name, name) # 같은 값을 여러 번 사용 
    print(formatted)
    
    >>>
    철수는 음식을 좋아해. 철수가 요리하는 모습을 봐요.

이런식으로 같은 값을 반복할 경우, 형식화할 값을 살짝 변경해야 하는 경우 실수하기도 쉽고 코딩하게이 성가시다.

예를들어 다음 예제에서는 title() 메서드를 뺴먹지 않고 여러 번 호출했지만, 어느 한 name에 대해서는 title() 메서드를 호출하고 다른 참조에 대해서는 메서드 호출을 잊어버릴수 있다.

    name = '영희'
    formatted = template %(name.title(), name.title())
    print(formatted)
    
    >>>
    영희는 음식을 좋아해. 영희가 요리하는 모습을 봐요.

이런 문제를 해결하기 위해 파이썬의 % 연산자에는 튜플 대신 딕셔너리를 이용해 형식화하는 기능이 추가됐다.

딕셔너리의 키는 형식 지정자에 있는 키 (ex : %(key)s)와 매치된다.

다음 예제는 이 기능을 사용해 출력에 아무런 영향을 주지 않으면서 형식화 식의 오른쪽에 있는 값의 순서를 바꿧다. 이렇게 앞에서 셜명한 첫 번째 문제점을 해결할 수 있다.

    key = 'my_var'
    value = 1.234
    
    old_way = '%-10s = %.2f' %(key, value)
    
    #원래 방식 
    new_way = '%(key)-10s = %(value).2f' % { 'value' : value, 'key' : key}
    
    reordered = '%(key)-10s = %(value).2f' % { 'key' : key, 'value' : value}
    
    assert old_way == new_way == reordered

형식화 식에 딕셔너리를 사용하면 여러 형식 지정자에 같은 키를 지정할 수 있어 같은 값을 반복하지 않아도 되므로 앞에서 설명한 세번째 문제점도 해결된다.

하지만 이런식으로 dict를 이용할 경우 표시해야 할 값을 살짝 바꿔야 할경우 표기할 내용이 많아져 가독성에 문제가 생긴다.

형식화 식에 딕셔너리를 사용하면 문장이 번잡스러워진다.

  1. 딕셔너리를 이용할 경우 각 키를 최소 두번씩 반복하게 된다. (한번은 형식 지정자 다른 한번은 딕셔너리 )

가독성을 해치는 문자를 제외하더라도, 이런 불필요한 중복으로 인해 딕셔너리를 사용하는 형식화 식이 너무 길어지게 된다.

        menu = {
        	'soup' : 'lentil',
        	'oyster' : 'tongtoung',
        	'special' : 'schnitizel',
        }
        
        template = ('Today\'s soup is %(soup)s,`
        						`buy one get two %(oyster)s oysters, `
        						`and our special entree is %(special)s.'
        					)
        formatted = template % menu
        print(formatted)

이 형식화 식이 어떤 결과를 만드는지 이해하려면 코드를 위아래로 계속 훑어 보면서 형식화 문자열과 딕셔너리를 뒤져아한다.

이런식의 불 연속성은 버그를 찾기 어렵게 만들고 가독성이 더 나빠진다.

내장함수 format과 str.format

파이썬 3부터는 %를 사용하는 C스타일 형식화 문자열 보다 더 표혁력이 좋은 고급 문자열 형식화 기능이 도입되었다.

이 기능은 format 내장 함수를 통해 모든 파이썬 값에 사용할 수 있다.

str.format() 메서드는 중괄호 {}를 사용하여 문자열 내에 값을 삽입합니다. 중괄호 안에는 삽입할 값에 대한 정보가 들어갑니다. 중괄호 내에는 인덱스 또는 변수 이름을 사용하여 값을 참조할 수 있습니다.

    name = "Alice"
    age = 25
    message = "안녕하세요, {}. 당신은 {}살입니다.".format(name, age)
    print(message)
    name = "Alice"
    age = 25
    height = 165.3
    
    # 위치 기반 포맷팅
    message1 = "안녕하세요, {}. 당신은 {}살이고 키는 {}cm입니다.".format(name, age, height)
    print(message1)
    
    # 인덱스 기반 포맷팅
    message2 = "안녕하세요, {0}. 당신은 {1}살이고 키는 {2}cm입니다.".format(name, age, height)
    print(message2)
    
    # 변수명 기반 포맷팅
    message3 = "안녕하세요, {name}. 당신은 {age}살이고 키는 {height}cm입니다.".format(name=name, age=age, height=height)
    print(message3)
    
    # 형식 지정 포맷팅
    message4 = "안녕하세요, {0}. 당신은 {1:.1f}살이고 키는 {2:.2f}cm입니다.".format(name, age, height)
    print(message4)
    
    >>>
    안녕하세요, Alice. 당신은 25살이고 키는 165.3cm입니다.
    안녕하세요, Alice. 당신은 25살이고 키는 165.3cm입니다.
    안녕하세요, Alice. 당신은 25살이고 키는 165.3cm입니다.
    안녕하세요, Alice. 당신은 25.0살이고 키는 165.30cm입니다.

새 스타일은 딕셔너리에서 작은 따옴표를 덜 사용하고, 형식 지정자에서 문자를 조금 덜 써도 되기 때문에 잡음이 약간 적다. 게다가 딕셔너리 키를 위치 지정자에 사용할 수 있다.

위치 지정자의 표현력 부족으로 인해 생기는 제약이 너무 커서 str의 format 메서드의 가치를 떨어뜨린다.

인터폴레이션을 통한 형식 문자열 (f- 문자열)

이러한 문제를 해결하기 위해 파이썬 3.6부터는 인터폴레이션 을 통한 형식 문자열 (f- 문자열) 이 도입됐다.

이 새로운 뭄법은 형식 문자열 앞에 f문자를 붙여야 한다. 바이트 문자열 앞에 b문자를 붙이고, raw 문자열에 r 문자를 붙이는 것과 비슷하다.

  • f-문자열은 형식 문자열의 표현력을 극대화
  • 형식화 문자열에서 키와 값을 불필요하게 중복 지정해야 하는 경우를 없애준다.
  • 형식화 식 안에서 현재 파이썬 영역에서 사용할 수있는 모든 이름을 자유롭게 참조할 수 있도록 허용함으로써 이런 간결함을 제공한다.
# 파이썬 3.6 이상에서는 f-문자열을 변사용하여 인터폴레이션을 할 수 있습니다.
name = "Alice"
message = f"Hello, {name}!"

f- 문자열을 활용한 다양한 예제

  • 변수 삽입
# 변수를 중괄호 {} 안에 넣어 변수 값을 문자열에 삽입합니다.
name = "Alice"
age = 25
message = f"안녕하세요, {name}님! 당신은 {age}살입니다."
print(message)

>>>
안녕하세요, Alice님! 당신은 25살입니다.
  • 수식 병가
# 수식을 중괄호 {} 안에서 평가하여 결과 값을 문자열에 삽입합니다.
x = 5
y = 3
result = f"더하기: {x + y}, 곱하기: {x * y}"
print(result)

>>>
더하기: 8, 곱하기: 15
  • 포맷 지정
# 소수점 자릿수를 지정하여 숫자를 문자열에 삽입합니다.
pi = 3.141592653589793
result = f"원주율: {pi:.2f}"
print(result)

>>>
원주율: 3.14
  • 변수 반복
# 리스트의 항목을 반복하여 문자열에 삽입합니다.
fruits = ['사과', '바나나', '딸기']
list_str = f"과일 목록: {', '.join(fruits)}"
print(list_str)

>>>
 과일 목록: 사과, 바나나, 딸기
  • 조건부 표현
# 조건부 표현식을 사용하여 변수에 따라 다른 문자열을 생성합니다.
score = 80
grade = f"학점: {'A' if score >= 90 else 'B'}"
print(grade)

>>>
학점: B

f-문자열이 제공하는 표현력, 간결성, 명확성을 고려할 떄 파이썬 프로그래머가 사용할 수 있는 최고의 형식화 옵션은 f-문자열이다. 값을 문자열로 형식화해야 하는 상황을 만나게 되면 다른 대안 대신 f-문자열을 선택하는것이 좋다.


정리

  • % 연산자를 사용하는 C 스타일 형식화 문자열은 여러 가지 단점과 번잡성이라는 문제가 있다.
  • str.foramt 메서드는 형식 지정자 미니 언어에서 유용한 개념 몇 가지를 제공했다 .하지만 이를 제외하고는 str.format 메서드도 C스타일 형식 묹바열의 문제점을 그대로 가지고 있으므로 가능한 str.format 사용을 피해야한다.
  • f-문자열은 값을 문자열 안에 넣는 새로운 구문으로 C스타일 형식화 문자열의 가장 큰 문제점을 해결해준다.
  • f-문자열은 간결하지만, 위치 지정자 안에 임의의 파이썬 식을 직접 포함시킬수 있으므로 매우 강력하다.
profile
Jr. DataEngineer

0개의 댓글