Batter way04

매일 공부(ML)·2022년 2월 1일
0

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


Preview

  • 파이썬 코드에는 문자열을 많이 쓴다.

  • 사용자 인터페이스 또는 명령줄 유틸리티에 메시지 표시

  • 파일과 소켓에 데이터를 쓰기

  • 잘못된 일 발생 시, Exception에 자세히 기록할 때 컴프리헨션을 이용해서 문자열 사용

  • 디버깅 발생 시, 대화형 혹은 repr문자열 사용


Formatting(형식화)

  • 미리 정의된 문자열에 데이터 값을 끼워서 보기 좋게 문자열을 저장하는 과정

  • 언어에 내장된 기능과 표준 라이브러를 통해 네 가지 방식으로 형식화

    • 한 가지를 제외하고 나머지는 단점이 존재

형식 문자열

  • 탬플릿에 끼워 넣을 값들은 연산자의 오른쪽에 단일 값 혹은 tuple 지정

  • 연산자 왼쪽에 있는 값을 끼워 넣을 자리르 표현하기 위해 형식 지정자 사용

  • % 형식화 연산자 사용
a = 0b10111011
b = 0xc5f

print('이진수: %d, 십육진수: %d' % (a,b))

#이진수: 187, 십육진수: 3167
  • 형식 지정자의 문법

    • C언어의 printf에 사용되는 대부분
    • 소수점 위치, 패딩, 채워 넣기, 좌우 정렬등 제공

파이썬에서 C 스타일 형식 문자열 사용 시 4가지 문제점

  • 형식화 식에서 오른쪽에 있는 tuple 내 데이터 값의 순서를 바꾸거나 값의 타입을 바꾸면 타입 변환이 불가능하므로 오류 발생

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

key = 'my_var'
value = 1.234
formatted = '%-10ss = %2.f' % (key, value)

print(formatted) # my_var = 1.23

  • 형식화 전에 값을 살짝 변경해야 하면 식을 읽기가 매우 어려워짐

    • 메시지를 쓸모있게 사용하려고 시도해도 가독성만 나빠진다.(tuple의 길이 증가)

  • 형식화 문자열에서 같은 값을 여러 번 사용 시 튜플에서 같은 값을 여러 번 반복해야하는 점입니다.

    • 가독성 나빠짐, 실수도 많고 코딩하기도 어렵다
  • 해결법

    • 파이썬의 % 연산자에는 튜플이 아닌 딕셔너리 사용하여 형식화 기능

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

    • 출력에 영향을 주지 않고 값의 순서 바뀌기 가능(첫 번째 문제 해결)

    • 형식화 식에 딕셔너리 사용 시 여러 형식 지정자에 같은 키를 지정할 수 있게 되어서 같은 값을 반복하지 않게 되어 세 번째 문제 해결


*첫 번째 문제 해결

key = 'may_var'

value = 1.234

old_way = '%-10s = %.2f' % (key,value)

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

*세 번째 문제 해결

name = '철수'
template = '%s는 음식을 좋아해. %s가 요리하는 모습을 봐요.'

before = template % (name, name) #튜플
template = '%(name)s는 음식을 좋아해. %(name)s가 요리하는 모습을 봐여.'

after = template % {'name':name} #딕셔너리

asserf before =- after

  • 딕셔너리 형식 문자열을 사용하면 다른 문제가 더 심해지거나 새로운 문제 생김

    • 형식화 식이 길어지고 시각적 잡음이 많아집니다.
    • 반복성이 증가되어 가독성 저하
for i, (item, count) in enumerate(pantry):

    before = '#%d: %-10s = %d' % (
        i + 1,
        item.title(),
        round(count))
        
        
    after = '#%(loop)d: %(item)-10s = %(count)d' % {
        'loop': i + 1,
        'item': item.title(),
        'count': round(count),
        
    }
    
    assert before == after

내장 함수 format와 str.format(첫 번째, 세 번째 문제 해결)


고급 문자열 형식화

  • format 내장 함수를 통해 모든 파이썬 값 사용
a = 1234.5678
formatted = format(a, ',.2f')
print(formatted) #1,234.57

b = 'my 문자열'
formatted = for(b, '^20s')
print(formatted) #*          my 문자열       *
  • str타입에 새로 추가된 format메서드를 호출하면 여러 값에 대해 기능 적용

    • 형식화 문자열의 위치 지정자는 format 메서드에 전달된 인자 중 순서상 같은 위치에 인자 가리키기
    • 각 위치 지정자에 콜론 뒤에 형식 지정자를 붙여 넣어서 문자열에 값을 넣을 시 어떤 형식으로 변환할지 정할 수 있다.
    • help('FORMATTING')로 모든 형식 지정자에 대해 정보
key = 'my_var'
value = 1.234

formatted = '{} ={}'.format(key,value)
print(formatted) # my_var = 1.234

#위치 지정자 적용


formatted = '{:<10} = {:2.f}'.format(key,value)
print(formatted) # my_var    = 1.23


# 그 위치에 해당하는 값: 뒤에 있는 형식 지정자를 FORMAT 내장 함수에 전달해 얻은 결과와 같다.

# 형식화된 전체 문ㅁ자열의 해당 위치 지정자 부분 대신

# 특별 메서드인 __format__을 사용해서 클래스별 형식화 방식으로 커스텀화
  • C 스타일 형식화 문자열에서 %문자 표시

    • %%로 이스케이프해야 하기
    • str.format아용하여 중괄호를 이스케이프하기
print('%.2f%%' % 12.5) # 12.50%
print('{} replaces {{}}'.format(1.23)) # 1.23 replaces {}

*C 스타일 첫 번째 문제 해결

  • format 메서드(위치 지정자 중괄호에 위치 인덱스)에 전달된 인자의 순서를 표현하는 위치 인덱스 전달

  • 순서를 바꾸지 않고 형식화 문자열 사용해서 형식화한 값의 출력 순서 변경 가능

formatted = '{1} = {0}'.format(key, value)
print(formatted) #12.34 = my_var

*C 스타일 세 번째 문제 해결

  • 형식화 문자열 안에서 같은 위치 인덱스 여러 번 사용 가능

  • format에 넘기는 인자에 값을 여러 번 반복 필요 없음

formatted = '{0}는 음식을 좋아해. {0}가 요리하는 모습을 봐요.'.format(name)

print(formatted) #철수는 음식을 좋아해. 철수가 요리하는 모습을 봐요

내장 함수 format와 str.format(두 번째, 네 번째 문제 해결 불가)


*C 스타일 두 번째 문제 해결 불가

  • C스타일의 형식화나 새로운 형식화 모두 가독성면에서 차이가 없다.

*C 스타일 네 번째 문제 해결 불가(키의 반복성 해결 불가)

  • str.format와 함께 사용하는 형식 지정자

    • 딕셔너리 키, 리스트 인덱스 조합하여 위치 지정자로 사용
    • 유니코드나 repr문자여롤 변화하여 값으로 이용
formatted = '첫 번째 글자는 {menu[oyster][0]!r}'.format(
    menu=menu)
print(formatted) #첫 번째 글자는 't'
  • str.format 메서드 사용하지 말 것을 권장하지만 f-문자열의 동작과 유용성을 이해하는데는 도움을 준다.

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

  • 형식 문자열 앞에는 f문자를 붙인다

  • 바이트 문자열 앞에는 b문자를 붙인다

  • raw문자열(이스케이프x) 앞에는 r문자를 붙인다.

  • 형식 문자열의 표현력 극대화

  • 키와 값을 불필요하게 중복 지정하는 경우 해결(C스타일 4번째 해결)

  • 형식화 식 안에서 파이썬 영역에서 사용할 수 있도록 모든 이름을 자유롭게 참조하도록 허용이 가능하는 간결함이 됩니다.

key = 'my_var'
value = 1.234

formatted = f'{key} = {value}'
print(formatted) # my_var = 1.234

#format 함수의 형식 지정자 안에서 콜론 뒤에 사용이 가능한 내장 미니 언어 사용 가능

# 값을 유니코드나 repr문자열로 변환하는 기능 사용

formatted = f'{key!r:<10} = {value:.2f}'
print(formatted) #my_var = 1.23

  • f-문자열이 C스타일이나 str.format메서드보다 항상 길이가 짧다
f_string = f'{key:<10} = {value:.2f}'

c_tuple = '%-10s = %.2f' % (key, value)

str_args = '{:<10} = {:.2f}'.format(key=key,
                                    value = value)
                                    
c_dict = '%(key)-10s = %(value).2f' % {'key':key
                                       'value':value}
                                       
assert c_tuple == c_dict == f_string
assert str_args == str_kw == f_string
  • 간결한 구문으로 표기가 가능하다(C스타일 두 번째 문제 해결)

    • 의미는 더 명확함
    • 연속된 문자열을 서로 연결해주는 기능 사용을 통해 나누기 가능
    • 한 줄보단 길지만 여러 줄 보단 깔끔하다.
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

총 정리
  • %연산자를 사용하는 C 스타일 형식화 문자열은 여러 가지 단점 및 번잡성이라는 문제가 있다.

  • str.format 메서드

    • 형식 지정자 미니언어: 유용한 개념 및 몇 가지 새로 제공
    • 이 외: C스타일 형식의 문제점을 그대로 가지고 있기에 되도록 피하기
  • f-문자열은 값을 문자열 안에 넣는 새로운 구문으로, C스타일 형식화 문자열의 가장 큰 문제점 해결

  • f-문자열은 간결하지만, 위치 지정자 안에 임의의 파이썬 식을 직접 포함 가능

  • f-문자열은 표현력, 간결성, 명확성 제공하기 가장 좋다.

  • 값을 문자열로 형식화 해야한다면 f-문자열을 사용해라

profile
성장을 도울 아카이빙 블로그

0개의 댓글