O string.Template é uma alternativa simples e segura para criar textos com campos substituíveis no Python. Em vez de misturar lógica complexa dentro de uma string, você define marcadores como $nome e fornece os valores separadamente. Esse modelo é especialmente útil em mensagens, arquivos de configuração, modelos de e-mail, notificações, relatórios e conteúdos editáveis por pessoas que não precisam conhecer a sintaxe completa das f-strings.
O que é string.Template
A classe Template pertence ao módulo padrão string. Ela trabalha com placeholders iniciados por cifrão. Um marcador pode ser escrito como $nome ou ${nome}. A segunda forma é útil quando o nome aparece junto de outros caracteres. O uso básico começa com from string import Template, seguido da criação do modelo e da chamada de substitute.
from string import Template
modelo = Template("Olá, $nome! Seu plano é ${plano}Premium.")
texto = modelo.substitute(nome="Ana", plano="Python ")
print(texto)O resultado é um texto final sem precisar concatenar valores manualmente. Isso reduz erros de pontuação e deixa o modelo mais legível. Para revisar conceitos básicos de texto, veja Strings em Python e f-strings no Python.
substitute e safe_substitute
O método substitute exige que todos os campos estejam disponíveis. Se faltar uma chave, ele gera KeyError. Esse comportamento é ótimo quando o preenchimento incompleto representa um erro que deve ser descoberto imediatamente.
modelo = Template("Pedido $codigo para $cliente")
modelo.substitute(codigo="A-10") # KeyError: clienteJá safe_substitute mantém o placeholder original quando o valor não existe. Ele é útil em editores de modelos, pré-visualizações e fluxos nos quais os dados chegam em etapas.
rascunho = modelo.safe_substitute(codigo="A-10")
print(rascunho) # Pedido A-10 para $clienteApesar do nome, safe_substitute não transforma conteúdo não confiável em conteúdo seguro para HTML, SQL ou shell. Ele apenas evita a exceção por chave ausente. Para tratamento de falhas, consulte Try Except no Python.
Quando usar Template em vez de f-string
F-strings são ideais quando o desenvolvedor controla o código e quer expressões, formatação numérica ou chamadas de função. Template é melhor quando o texto pode ser editado fora do código, por exemplo em um arquivo, banco de dados ou painel administrativo. Ele oferece uma linguagem de modelo deliberadamente limitada. Essa limitação é uma vantagem: quem edita o texto não consegue executar expressões Python dentro do marcador.
Em uma f-string, expressões são avaliadas no momento da execução. Em um Template, os marcadores são apenas nomes. Isso separa dados e apresentação. O modelo pode ser armazenado, revisado, traduzido e reutilizado. Para projetos com arquivos externos, veja como ler arquivos TXT e JSON no Python.
Preenchendo com dicionários
O método aceita um mapping como primeiro argumento. Isso facilita integrar dados vindos de APIs, formulários ou arquivos JSON.
dados = {"produto": "Curso de Python", "valor": "R$ 99"}
modelo = Template("$produto disponível por $valor")
print(modelo.substitute(dados))Também é possível combinar mapping e argumentos nomeados. Os argumentos nomeados têm prioridade. Essa técnica permite definir valores padrão e substituir apenas campos específicos em determinado contexto.
padrao = {"empresa": "Academify", "canal": "site"}
texto = Template("$empresa atende pelo $canal")
print(texto.substitute(padrao, canal="WhatsApp"))Validando campos antes de substituir
Em sistemas maiores, convém descobrir quais placeholders existem no modelo antes do preenchimento. Versões recentes do Python oferecem métodos como is_valid() e get_identifiers(). O primeiro informa se a sintaxe do modelo é válida; o segundo retorna os nomes encontrados.
modelo = Template("Olá $nome, pedido $codigo")
if not modelo.is_valid():
raise ValueError("Modelo inválido")
campos = modelo.get_identifiers()
faltantes = set(campos) - {"nome", "codigo"}
print(campos, faltantes)Essa validação é útil antes de salvar um template criado por usuário. Você pode permitir somente campos aprovados, rejeitar nomes desconhecidos e mostrar uma mensagem amigável. Também ajuda a criar testes automatizados para garantir que uma tradução continue usando o conjunto correto de variáveis.
Personalizando o delimitador
A classe pode ser estendida para alterar o delimitador. Isso resolve conflitos quando o cifrão já possui outro significado no domínio do texto.
class ModeloArroba(Template):
delimiter = "@"
modelo = ModeloArroba("Olá @nome")
print(modelo.substitute(nome="Carlos"))Também é possível personalizar a expressão regular de identificação, mas essa decisão deve ser tomada com cuidado. Quanto mais complexa a sintaxe, maior o custo de manutenção. Na maioria dos projetos, mudar apenas o delimitador ou manter o padrão é suficiente.
Exemplo: gerador de e-mails
Considere um sistema que envia mensagens em vários contextos. O assunto e o corpo podem ficar em arquivos separados. O código carrega o modelo, valida os identificadores e aplica os dados.
from pathlib import Path
from string import Template
def renderizar(caminho, dados):
conteudo = Path(caminho).read_text(encoding="utf-8")
modelo = Template(conteudo)
if not modelo.is_valid():
raise ValueError("Template com sintaxe inválida")
permitidos = set(dados)
desconhecidos = set(modelo.get_identifiers()) - permitidos
if desconhecidos:
raise ValueError(f"Campos não permitidos: {desconhecidos}")
return modelo.substitute(dados)Esse design mantém o conteúdo fora da função e facilita a revisão por equipes de marketing ou suporte. A função continua responsável por validação, codificação e preenchimento. Para organização de caminhos, consulte pathlib no Python.
Cuidados de segurança
Template evita a avaliação de expressões Python, mas não substitui validações específicas do destino. Se o resultado será exibido em HTML, aplique escape de HTML aos valores. Se será usado em uma consulta SQL, utilize parâmetros do driver; nunca monte SQL por substituição textual. Se será enviado ao terminal, evite concatenar comandos e prefira listas de argumentos no subprocess.
Outro cuidado é limitar os campos aceitos. Um modelo vindo de usuário pode solicitar nomes inesperados e revelar dados que estavam no dicionário. Em vez de passar um objeto inteiro com informações sensíveis, crie um mapping mínimo contendo somente os valores necessários.
Testando modelos
Testes devem cobrir o caminho completo e os erros esperados. Verifique modelos válidos, chaves ausentes, placeholders repetidos, delimitadores escapados com $$ e caracteres junto aos identificadores.
def test_modelo():
modelo = Template("$nome pagou $$ $valor")
assert modelo.substitute(nome="Lu", valor="20") == "Lu pagou $ 20"
Também teste traduções. Um modelo em espanhol pode usar os mesmos nomes internos, embora o texto mude. Isso evita que a aplicação precise criar dicionários diferentes para cada idioma.
Boas práticas
Prefira nomes de placeholder claros, como $nome_cliente, em vez de abreviações. Documente os campos disponíveis perto do editor de templates. Valide o modelo no momento do cadastro, não apenas no envio. Use substitute em produção quando dados incompletos devem bloquear a operação e reserve safe_substitute para prévias ou rascunhos.
Mantenha formatação complexa no código. Se um valor monetário precisa de duas casas decimais, formate-o antes de colocá-lo no mapping. Dessa forma, o template permanece simples e previsível.
Conclusão
string.Template oferece uma solução pequena, legível e adequada para conteúdo configurável. Ele não pretende substituir mecanismos completos como Jinja, mas atende muito bem mensagens, notificações e arquivos simples. Ao validar identificadores, limitar dados disponíveis e aplicar escape adequado ao destino, você cria modelos fáceis de editar sem misturar apresentação com lógica de execução.
Documentação oficial: Template strings no Python. Referência de segurança para HTML: html.escape.







