PEP 750 – 템플릿 문자열(t-strings) 승인
(peps.python.org)- 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><script>alert('evil')</script></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}"
)
템플릿 문자열 연결
-
+
연산자로Template
과str
,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 코드가 더 장황함