2 pontos por GN⁺ 2025-04-11 | 3 comentários | Compartilhar no WhatsApp
  • A PEP 750 introduz no Python um novo literal de string: strings de template (t"...")
  • É uma forma generalizada de f-string, que cria o tipo Template e permite processar previamente a combinação entre a string e os valores interpolados
  • Pode ser útil em templates web, verificações de segurança e DSLs (Domain-Specific Languages)

Relação com outras PEPs

  • As f-strings foram introduzidas na PEP 498, e sua sintaxe foi expandida na PEP 701
  • A PEP 501 propôs strings de template genéricas (i-strings), mas ficou em espera
  • A atual PEP 750 é uma forma simplificada e generalizada da PEP 501, evoluindo a partir das ideias existentes

Motivação e necessidade

  • As f-strings são simples, mas como não permitem pré-processar os valores interpolados, podem gerar problemas de segurança
  • Há preocupação com vulnerabilidades como injeção de SQL e ataques XSS
  • Com strings de template, é possível processar os valores interpolados antes e usá-los com segurança

Exemplo:

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

Especificação das strings de template

Literais de string de template

  • Definidos com o prefixo t ou T
  • Avaliados como o tipo string.templatelib.Template
  • Suportam sintaxe semelhante à de f-strings, inclusive com aninhamento
  • Podem ser combinados com o prefixo r (rt, tr)
  • Não podem ser combinados com os prefixos u e b
  • Não é permitido misturar f-strings e strings de template

Tipo Template

  • É um tipo imutável e possui os seguintes atributos:
    • strings: tupla de fragmentos de string
    • interpolations: tupla de objetos de valores interpolados
    • values: tupla com os valores interpolados
    • __iter__(): iterador que retorna strings e valores interpolados em sequência

Tipo Interpolation

  • value: resultado avaliado
  • expression: string da expressão interpolada original
  • conversion: forma de conversão (r, s, a ou None)
  • format_spec: string de formatação

Exemplo:

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

Especificador de depuração =

  • t"{value=}" é interpretado como t"value={value!r}"
  • Os espaços também são preservados (t"{value = }""value = {value!r}")

Concatenação de strings de template

  • O operador + permite combinar Template com str, e Template com Template
  • O resultado da concatenação é sempre do tipo Template
  • A concatenação implícita de strings (t"Hello " t"World") também é possível

Como processar strings de template

Exemplo: função de transformação para minúsculas/maiúsculas

  • 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)

Exemplo: implementação com o mesmo processamento de f-string

  • A função f() pode gerar o mesmo resultado que uma f-string

Exemplo: logging estruturado

  • Com strings de template, é possível emitir ao mesmo tempo a mensagem de log e os valores estruturados
  • Pode ser implementado com StructuredMessage ou uma subclasse de logging.Formatter

Exemplo: processamento de template HTML

  • A função html() trata o conteúdo com escape adequado ou como atributo, dependendo da posição de inserção
  • Também há suporte a templates aninhados

Padrões avançados de uso

  • Recomenda-se o uso de correspondência estrutural de padrões (instrução match)
  • Strings estáticas podem ser usadas como chave de cache, permitindo memoização eficiente
  • Também é possível analisar e processar via representações intermediárias, como AST
  • Para avaliação Lazy ou Async, podem ser usados lambda e await

Relação entre strings de template e strings de formatação existentes

  • É possível definir funções de template de forma semelhante ao .format() tradicional
  • Também é possível um from_format() que analisa uma string externa e a converte em Template

Compatibilidade, segurança e aprendizado

  • Em versões antigas do Python, a sintaxe pode gerar erro
  • Em termos de segurança, o processamento por template aumenta a proteção
  • A sintaxe, semelhante à de f-strings, facilita o aprendizado

Por que uma nova abordagem de templates?

  • Templates existentes, como Jinja, costumam ser voltados para personalização ou para designers
  • É necessário suporte no próprio Python para que desenvolvedores possam lidar diretamente com templates
  • Isso permite aproveitar vantagens como expressividade e verificação de tipos

Resumo dos padrões de exemplo

  • Correspondência estrutural de padrões e correspondência em atributos internos
  • Reutilização de templates como se fossem funções
  • Suporte a templates aninhados
  • Suporte a avaliação Lazy/Async
  • Otimização de cache com separação entre partes estáticas e dinâmicas

Outras considerações de design

  • Templates não são convertidos em string, e __str__() não é implementado
  • As classes relacionadas são fornecidas no módulo string.templatelib
  • Template e Interpolation são comparados com base na identidade do objeto
  • As operações == e < não são suportadas

Implementação de referência e exemplos

Ideias rejeitadas

  • Uso de prefixos arbitrários (my_tag"...")
  • Avaliação adiada de todas as expressões interpoladas
  • Implementação via protocolo
  • Redefinição de __eq__ e __hash__
  • Restauração completa da string original
  • Adição do tipo Decoded
  • Suporte a strings de template binárias
  • Recurso para especificar o tipo de formato ("html", "sql" etc.)
  • Limitação da concatenação de strings
  • Permissão para conversores arbitrários (!x)

3 comentários

 
carnoxen 2025-04-11

A formatação mais satisfatória, para mim, só existe em JS e Python. Outras linguagens ficam meio...

 
kandk 2025-04-11

Haverá uma maneira óbvia de fazer isso — e, de preferência, apenas uma.

 
GN⁺ 2025-04-11
Comentários no Hacker News
  • É interessante como diferentes linguagens lidam com formatação de strings

    • Java está tentando adicionar f/t-strings, mas vem enfrentando dificuldades por causa de um perfeccionismo de querer resolver todos os problemas
    • Os desenvolvedores de Go parecem ter praticamente ignorado essa questão sem dar muita atenção a ela
    • Python adotou uma abordagem equilibrada, discutindo novos métodos de formatação de strings e escolhendo implementações adequadas para uso
    • É difícil discordar da abordagem do Python, e ela tem gerado valor com .format(), f-strings e t-strings
  • Nick Humrich é um dos autores que reescreveram a PEP 501 para introduzir t-strings e está muito feliz com a aceitação desta PEP

    • Começou a trabalhar na PEP 501 há 4 anos
  • Não há certeza de que um recurso no nível da linguagem tenha valor

    • O mesmo resultado pode ser obtido com uma função que retorna uma f-string
    • Se você quer segurança contra injeção, basta usar um tipo de tag e uma função de sanitização que retorne uma string
    • É conciso, mas distinguir execução imediata e execução adiada com uma única letra pode dificultar a leitura para quem não está acostumado com Python
  • Gosta de f-strings, mas há o problema de não ser possível adiar a avaliação

    • Há casos em que é preciso usar str.format, o que é incômodo
  • Como mantenedor do lit-html, acha interessante a semelhança com template literals com tags do JavaScript

    • A forma como a classe Template do Python separa a função tag e os argumentos é peculiar em relação ao JavaScript
    • Em estruturas de templates aninhados, talvez a função html() não seja necessária
  • Há expectativa de que, assim como os template literals com tags do JavaScript ajudam com autoescape de HTML e parametrização de SQL, isso também seja aplicado ao Python

  • Há a opinião de que Python está se transformando em PHP

    • f-strings e t-strings adicionam complexidade à linguagem
    • Considera string.format o ideal, e % também é aceitável por ser usado há muito tempo
    • Gostaria que a equipe da linguagem se concentrasse em coisas mais importantes
  • Reclamação sobre continuar adicionando coisas novas à linguagem

    • A linguagem passa a sensação de ter sido projetada por um comitê
  • Há a opinião de que esta PEP é semelhante ao P1819 do C++

  • Há a opinião de que o código da PEP é excessivamente verboso

    • Parece que Python está expressando excesso de coisas desnecessárias, em vez de ser um pseudocódigo executável
    • Em comparação com Ruby, o código em Python é mais verboso