형식화 식에서 오른쪽에 있는 tuple 내 데이터 값의 순서를 바꾸거나 값의 타입을 바꾸면 타입 변환이 불가능하므로 오류가 발생 할 수 있다.
key = "my_var"
value = 1.234
show = "%-10s = %.2f" %(key, value)
print(show)
-> my_var = 1.23
reshow = "%-10s = %.2f" %(value, key)
-> TypeError: must be real number, not str
⚠ 출력할 데이터 타입 다르기 때문에 에러가 발생한다.
reshow_string = "%.2f = %-10s" %(key, value)
-> TypeError: must be real number, not str
형식 문자열에 순서를 바꿔도 같은 오류가 발생한다.
✍🏻이런식의 형식 문자열 사용하면 좌우가 잘 맞는지 계속 검사해야하는 번거로움이 있다. 검사하는 과정에서도 실수 할 수도 있다.
형식화 하기 전에 값을 살짝 변경해야 한다면 식을 읽기가 매우 어려워진다.
fruit = [
("바나나", 1.25),
("딸기", 3.6),
("블루베리", 2.5),
]
for idx, (item,price) in enumerate(fruit):
print("#%d: %-10s = %.2f" %(idx, item, price))
->
#0: 바나나 = 1.25
#1: 딸기 = 3.60
#2: 블루베리 = 2.50
이 코드에서 약간에 변화를 줘서 1번부터 시작하게 만들고 싶다. 코드를 수정하면
fruit = [
("바나나", 1.25),
("딸기", 3.6),
("블루베리", 2.5),
]
for idx, (item,price) in enumerate(fruit):
print("#%d: %-10s = %.2f" % (
idx + 1,
item.title(),
round(price)
))
이런 식으로 코드를 수정해야 한다.
✍🏻이런식으로 코드를 수정할 경우 형식화 식에 있는 tuple에 길이가 너무 길어져서 여러 줄에 나줘서 써야 하는 문제가 발생한다. 그로 인해 가독성이 나빠진다.
형식화 문자열에서 같은 값을 여러 번 사용하고 싶다면 튜플에서 같은 값을 여러 번 반복해야 한다.
template = "%s는 음식을 좋아해. %s가 요리하는 모습을 봐요."
name = "철수"
formatted = template % (name, name)
print(formatted)
->
철수는 음식을 좋아해. 철수가 요리하는 모습을 봐요.
name이란 변수를 반복해서 사용해야 한다. 이런식의 코딩은 실수하기 쉽고 가독성도 안좋다. title 메서드를 사용할 때도 하나는 title을 쓰고 실수로 다른 하나에는 안 쓰는 경우가 발생 할 수 있다
name = "철수"
formatted = template % (name.title(), name)
네번째 문제점은 C 스타일 형식화 식의 딕셔너리를 사용하는 방식이다. 이러한 방식은 첫번째 문제점과 형식 지정자에 같은 키를 지정할 수 있어서 같은 값을 반복하지 않아 세번째 문제점도 해결할 수 있다. 하지만 딕셔너리를 사용하면 문장이 번잡스러워 진다.
soup = "lentil"
formatted = "Today\'s soup is %(soup)s." % {'soup' : soup}
print(formatted)
이런 불필요한 중복으로 인해 딕셔너리를 사용하는 형식화 식이 너무 길어진다.
menu = {
'soup' : 'lentil',
'oyster': 'tongyoung',
'special': 'schnitzel',
}
template = (
'today\'s soup is %(soup)s,'
'buy one get two %(oyster)s oyster,'
'and our special entree is %(special)s.'
)
formatted = template % menu
print(formatted)
이런식의 코딩 스타일은 이해하기 위해 긴 코드를 여러번 위아래로 훑으면서 형식화 문자열과 딕셔너리를 뒤져야 한다. 도중에 약간에 코드를 수정한다면 가독성도 안좋고 버그 찾기도 힘들다.
파이썬3 부터는 오랜된 C스타일 형식화 문자열보다 더 표현력이 좋은 고급 문자열 형식화 기능이 도입됐다.
사용 법
a = 1234.5678
formatted = format(a, ",.2f")
print(formatted)
b = "this is 문자열"
formatted = format(b,'^20s')
print(formatted)
str타입에 새로 추가된 format 메서드를 호출하면 여러값을 한꺼번에 이 기능을 적용할 수 있다.
key = "my_var"
value = 1.234
formatted = '{} = {}'.format(key, value)
print(formatted)
->
my_var = 1.234
이런식으로 사용하면 C 스타일과 다르게 데이터값 변수 위치를 신경 안써도 된다. 단순하게 순서대로 입력된다고 생각하면 된다. 값을 넣을 때 어떤 형식으로 변환할 지 정할 수 있다. 만약 따로 순서를 정하고 싶다는 아래 코드처럼 번호를 입력해주면 된다.(✔첫번째 문제점 해결)
formatted = "{1} = {0}".format(key, value)
print(formatted)
->
1.234 = my_var
같은 위치 인덱스를 여러번 사용할 수도 있다.
name = "john"
formatted = "{0}는 음식을 좋아해. {0}가 요리하는 모습을 봐요".format(name)
세번째 문제점 해결
😀format은
첫번째 문제점과 세번째 문제점을 해결 할 수 있다.
하지만...
🤔두번째 문제점과 네번째 문제점은 해결되지 않는다.
for i, (item, count) in enumerate(pantry):
old_style = "%d: %-10s = %d" %(
i+1,
item.title(),
round(count)
)
for i, (item, count) in enumerate(pantry):
new_style = "#{}: {<10s} = {}".format(
i+1,
item.title(),
round(count)
)
두번째 문제점인 형식이 길어져서 가독성이 안 좋아지는 문제는 해결되지 않는다.
old_template = (
'Today \`s soup is %{soup}s,'
)
old_formatted = old_template % {
'soup': 'lentil'
}
new_template = (
'Today \'s soup is {soup}
)
new_formatted = new_template.format(
soup: 'lentil'
)
네번째 문제점도 별차이 없다.
위치 지정자의 표현력 부족으로 인해 생기는 제약이 너무 커서 str의 format 메서드의 가치를 떨어뜨린다.
파이썬 3.6부터 이러한 문제점들을 해결하기 위해 인터포레이션을 통한 형식 문자열(f-문자열)이 도입됐다. 새로운 방식은 문자열 앞에 f 문자를 붙여야 한다.
f-문자열은 형식 문자열의 표현력을 극대화하고, 앞으로 설명한 네번째 문제점인 형식화 문자열에서 키와 값을 불필요하게 중복 지정해야 하는 경우를 없애준다.
key = "my_var
value = 1.234
formatted = f'{key} = {value}'
print(formatted)
➜
my_var = 1.234
formatted = f'{key!r:<10} = {value:.2f}'
print(formatted)
➜
'my_var' = 1.23
for i, (item, count) in enumerate(pantry):
old_style = '#%d: %-10s = %d' % (
i + 1,
item.title(),
round(count)
)
new_style = '#{}: {:<10s} = {}'.format(
i + 1,
item.title(),l
round(count)
)
f_string = f'#{i+1}: {item.title():<10s} = {round(count)}'
😀 format 메서드 C스타일과 비교해도 f-문자열이 휄씬 짧아지고 가독성이 좋다.
for i, (item, count) in enumerate(pantry):
print(f'#{i+1}'
f'{item.title():<10s} = '
f'{round(count)}'
)
➜
#1: 아보카도 = 1
#2: 바나나 = 2
#3: 체리 = 15
😀 한줄 보다 긴 코드가 되지만, 다른 접근 방식으로 표현한 여러 줄 코드보다 휄씬 깔끔하다.
places = 3
number = 1.23456
print(f'내가 고른 숫자는 {number:.{places}f}')
➜
내가 고른 숫자는 1.235
✨f-문자열이 제공하는 표현력, 간결성, 명확성을 고려할 때 파이썬 프로그래머가 사용할 수 있는 형식화 옵션 중에서 f-문자열이 최고다. 값을 문자열로 형식화해야 하는 상황을 만나게 되면 다른 다안 대신 f-문자열을 택하라
✔이 글은 코딩의 기술 - 이펙티브 파이썬을 참고하여 작성했습니다.