2P by GN⁺ 9일전 | ★ favorite | 댓글 3개
  • PEP 750은 Python에 새로운 문자열 리터럴인 템플릿 문자열(t"...") 을 도입함
  • f-string의 일반화된 형태로, Template 타입을 생성하여 문자열과 삽입 값을 결합 전 처리할 수 있는 기능 제공
  • 웹 템플릿, 보안 검사, DSL(Domain-Specific Language) 등에 유용하게 사용 가능함

다른 PEP들과의 관계

  • f-string은 PEP 498로 도입되었고, PEP 701에서 문법이 확장됨
  • PEP 501은 일반 템플릿 문자열(i-string)을 제안했지만 보류됨
  • 현재 PEP 750은 PEP 501을 단순화 및 일반화한 형태로, 기존 아이디어를 기반으로 발전됨

동기 및 필요성

  • f-string은 간단하지만, 삽입 값을 사전에 가공할 수 없어 보안상 문제 발생 가능
  • SQL 삽입, XSS 공격 등 보안 취약점 유발 우려 있음
  • 템플릿 문자열을 사용하면 삽입 값을 사전에 가공하여 안전하게 사용할 수 있음

예시:

  • evil = "<script>alert('evil')</script>"
  • template = t"<p>{evil}</p>"
  • assert html(template) == "<p>&lt;script&gt;alert('evil')&lt;/script&gt;</p>"

템플릿 문자열의 사양

템플릿 문자열 리터럴

  • 접두사 t 또는 T를 사용해 정의
  • string.templatelib.Template 타입으로 평가됨
  • f-string과 유사한 문법 지원, 중첩도 가능
  • r 접두사와 조합 가능 (rt, tr)
  • u, b 접두사와는 조합 불가
  • f-string과 템플릿 문자열은 혼합 사용 불가

Template 타입

  • 불변 타입이며, 다음 속성을 가짐:
    • strings: 문자열 조각들의 튜플
    • interpolations: 삽입값 객체들의 튜플
    • values: 삽입값들의 값 튜플
    • __iter__(): 문자열과 삽입값을 순서대로 반환하는 이터레이터

Interpolation 타입

  • value: 평가된 결과
  • expression: 원래 삽입 표현식 문자열
  • conversion: 변환 방식 (r, s, a 또는 None)
  • format_spec: 서식 문자열

예시:

  • name = "World"
  • template = t"Hello {name!r}"
  • assert template.interpolations[0].conversion == "r"

디버그 지정자 =

  • t"{value=}"t"value={value!r}"로 해석됨
  • 공백도 그대로 보존됨 (t"{value = }""value = {value!r}")

템플릿 문자열 연결

  • + 연산자로 Templatestr, Template 간의 결합 가능
  • 연결 결과는 항상 Template 타입
  • 묵시적 문자열 연결(t"Hello " t"World")도 가능

템플릿 문자열 처리 방법

예시: 대문자 처리 함수

  • def lower_upper(template):
    • parts = []
    • for s in template:
      • if isinstance(s, str): parts.append(s.lower())
      • else: parts.append(str(s.value).upper())
    • return "".join(parts)

예시: f-string과 동일한 처리 구현

  • f() 함수로 f-string과 동일한 결과 생성 가능

예시: 구조화된 로깅

  • 템플릿 문자열을 사용하면 로그 메시지와 구조화된 값들을 동시에 출력 가능
  • StructuredMessage 또는 logging.Formatter 서브클래스로 구현 가능

예시: HTML 템플릿 처리

  • html() 함수는 삽입 위치에 따라 내용을 적절히 escape 또는 속성으로 처리
  • 중첩 템플릿도 지원

고급 사용 패턴

  • 구조적 패턴 매칭 사용 권장 (match 문)
  • 정적 문자열은 캐시 키로 사용, 효율적 메모이제이션 가능
  • AST 등 중간 표현으로 파싱해 처리 가능
  • Lazy 또는 Async 평가를 위해 lambda, await 사용 가능

템플릿 문자열과 기존 포맷 문자열의 관계

  • 기존 .format()과 유사한 방식으로 템플릿 함수 정의 가능
  • 외부 문자열을 파싱하여 Template으로 변환하는 from_format()도 가능

호환성, 보안, 학습

  • 구 버전 Python에서는 문법 오류 발생 가능
  • 보안상 템플릿 처리가 안전성을 높임
  • f-string과 유사한 문법으로 학습이 쉬움

왜 새로운 템플릿 접근 방식인가?

  • 기존 Jinja 같은 템플릿은 사용자 정의 또는 디자이너 대상
  • 템플릿을 개발자가 직접 다룰 수 있도록 Python 언어 차원에서 지원 필요
  • 표현력과 타입 검사 등의 장점 활용 가능

예시 패턴 정리

  • 구조적 패턴 매칭과 하위 속성 매칭
  • 템플릿을 함수처럼 재사용
  • 중첩 템플릿 지원
  • Lazy/Async 평가 지원
  • 정적/동적 분리로 캐시 최적화

기타 설계 고려 사항

  • 템플릿은 문자열로 변환되지 않으며, __str__() 미구현
  • string.templatelib 모듈에서 관련 클래스 제공
  • Template, Interpolation은 객체 동일성 기준으로 비교됨
  • == 또는 < 연산은 지원하지 않음

참조 구현 및 예제

거절된 아이디어

  • 임의의 접두사 사용 (my_tag"...")
  • 모든 삽입 표현식의 지연 평가
  • 프로토콜로 구현
  • __eq__, __hash__ 재정의
  • 원본 문자열 완전 복원
  • Decoded 타입 추가
  • 바이너리 템플릿 문자열 지원
  • 포맷 종류("html", "sql" 등) 지정 기능
  • 문자열 연결 제한
  • 임의의 변환자(!x) 허용

가장 만족스러운 포매팅은 자스와 파이썬밖에 없네요. 다른 언어는 좀...

명확한, 그리고 가급적이면 유일한 명백한 방법이 있을 것이다. (There should be one-- and preferably only one --obvious way to do it.)

Hacker News 의견
  • 다양한 언어들이 문자열 포맷팅을 다루는 방식이 흥미로움

    • Java는 f/t-strings를 추가하려고 노력 중이나, 모든 문제를 해결하려는 완벽주의로 인해 어려움을 겪고 있음
    • Go 개발자들은 이 문제를 거의 고려하지 않고 무시한 것으로 보임
    • Python은 균형 잡힌 접근 방식을 취해 새로운 문자열 포맷팅 방법을 논의하고 적절한 구현을 선택해 사용 중임
    • Python의 접근 방식에 동의하지 않을 수 없으며, .format(), f-strings, t-strings를 통해 가치를 얻고 있음
  • Nick Humrich는 PEP 501을 재작성하여 t-strings를 도입한 저자 중 한 명이며, 이 PEP의 수용에 매우 기뻐하고 있음

    • 4년 전부터 PEP 501 작업을 시작했음
  • 언어 수준의 기능이 가치 있는지 확신하지 못함

    • f-string을 반환하는 함수로 같은 결과를 얻을 수 있음
    • 주입 안전성을 원한다면 태그 타입과 문자열을 반환하는 정화 함수를 사용하면 됨
    • 간결하지만, 단일 문자로 즉시 실행과 지연 실행을 구분하는 것은 Python에 익숙하지 않은 사람들에게 읽기 어려움을 줄 수 있음
  • f-strings를 좋아하지만, 평가를 지연할 수 없는 문제가 있음

    • str.format을 사용해야 하는 경우가 있어 불편함
  • lit-html의 유지보수자로서 JavaScript의 태그 템플릿 리터럴과 유사한 점이 흥미로움

    • Python의 Template 클래스가 JavaScript의 태그 함수와 인수를 분리하는 방식이 독특함
    • 중첩된 템플릿 구조에서 html() 함수가 필요하지 않을 수 있음
  • JavaScript의 태그 템플릿 리터럴이 HTML 자동 이스케이프나 SQL 매개변수화에 도움이 되는 점이 Python에도 적용될 것 같아 기대됨

  • Python이 PHP로 변하는 것 같다는 의견

    • f-strings와 t-strings가 언어에 복잡성을 더함
    • string.format이 최적이라고 생각하며, %도 오랫동안 사용되어 온 만큼 수용 가능함
    • 언어 팀이 더 중요한 것에 집중하길 바람
  • 언어에 계속해서 새로운 것을 추가하는 것에 대한 불만

    • 언어가 위원회에 의해 설계된 것처럼 느껴짐
  • 이 PEP가 C++의 P1819와 유사하다는 의견

  • PEP의 코드가 너무 장황하다는 의견

    • Python이 실행 가능한 의사 코드가 아닌 과도한 불필요함을 표현하는 것 같음
    • Ruby의 코드와 비교하여 Python 코드가 더 장황함