f-strings em Python: O que São e Como Funcionam | Python Brasil
Guia completo de f-strings em Python: format spec mini-language, debug com =, multiline, segurança vs Template strings, Python 3.12 e performance.
O que são f-strings?
As f-strings (formatted string literals) são a forma mais moderna e eficiente de formatar strings em Python. Introduzidas no Python 3.6 pela PEP 498, elas permitem inserir expressões Python diretamente dentro de strings usando chaves {}.
Para criar uma f-string, basta colocar a letra f (ou F) antes das aspas. Tudo dentro de {} é avaliado como código Python no momento da execução — não é apenas substituição de texto, é avaliação de expressões completas.
Como o Python compila f-strings internamente
F-strings não são templates processados em tempo de execução como str.format(). Elas são compiladas pelo interpretador Python para chamadas de concatenação de strings, o que as torna significativamente mais rápidas:
# Esta f-string:
nome = "Maria"
resultado = f"Olá, {nome}!"
# É compilada aproximadamente para:
resultado = "Olá, " + str(nome) + "!"
# Mais precisamente, o bytecode usa FORMAT_VALUE e BUILD_STRING
# que são instruções nativas do interpretador — sem overhead de parsing
import dis
dis.dis('f"Olá, {nome}!"')
# LOAD_NAME 0 (nome)
# FORMAT_VALUE 0
# BUILD_STRING 2
Exemplos básicos e expressões
nome = "João"
idade = 30
altura = 1.75
# Variáveis simples
print(f"Nome: {nome}, Idade: {idade}")
# Nome: João, Idade: 30
# Expressões aritméticas
print(f"Ano de nascimento aproximado: {2025 - idade}")
# Chamadas de método
print(f"Nome em maiúsculas: {nome.upper()}")
# Condicionais (ternário)
status = f"{'maior' if idade >= 18 else 'menor'} de idade"
print(status) # maior de idade
# Chamadas de função
print(f"Raiz quadrada de 2: {2 ** 0.5:.4f}")
# Acesso a atributos e índices
lista = [10, 20, 30]
print(f"Primeiro: {lista[0]}, Último: {lista[-1]}")
dicionario = {'chave': 'valor'}
print(f"Chave: {dicionario['chave']}")
A mini-linguagem de formatação (format spec)
A parte mais poderosa das f-strings é o format spec — uma mini-linguagem para controlar a apresentação de valores, colocada após : dentro das chaves:
# Sintaxe: {valor:[[fill]align][sign][#][0][width][grouping][.precision][type]}
# Alinhamento — fill, align, width
nome = "Python"
print(f"|{nome:<15}|") # |Python | — alinhado à esquerda
print(f"|{nome:>15}|") # | Python| — alinhado à direita
print(f"|{nome:^15}|") # | Python | — centralizado
print(f"|{nome:-^15}|") # |----Python-----| — centralizado com '-' como fill
# Números inteiros
n = 42
print(f"{n:d}") # 42 — decimal (padrão)
print(f"{n:b}") # 101010 — binário
print(f"{n:o}") # 52 — octal
print(f"{n:x}") # 2a — hexadecimal minúsculo
print(f"{n:X}") # 2A — hexadecimal maiúsculo
print(f"{n:#b}") # 0b101010 — com prefixo
print(f"{n:08b}") # 00101010 — zero-padded com 8 dígitos
# Números com agrupamento de milhar
valor = 1_234_567.89
print(f"{valor:,.2f}") # 1,234,567.89 — vírgula como separador
print(f"{valor:_.2f}") # 1_234_567.89 — underscore como separador
print(f"{valor:+.2f}") # +1234567.89 — sempre mostra o sinal
# Porcentagem
taxa = 0.1523
print(f"{taxa:.1%}") # 15.2% — multiplica por 100 e adiciona %
# Notação científica
pi_grande = 3.14159e10
print(f"{pi_grande:.3e}") # 3.142e+10
print(f"{pi_grande:.3E}") # 3.142E+10
Conversões: !r, !s e !a
Os modificadores de conversão são aplicados antes do format spec:
class Usuario:
def __init__(self, nome):
self.nome = nome
def __str__(self):
return f"Usuário: {self.nome}"
def __repr__(self):
return f"Usuario(nome={self.nome!r})"
u = Usuario("Ana")
texto_especial = "linha1\nlinha2"
# !s — usa str() — mesmo que sem modificador
print(f"{u!s}") # Usuário: Ana
# !r — usa repr() — útil para debug, mostra aspas e caracteres de escape
print(f"{u!r}") # Usuario(nome='Ana')
print(f"{texto_especial!r}") # 'linha1\nlinha2'
# !a — usa ascii() — escapa caracteres não-ASCII
print(f"{'café'!a}") # 'caf\xe9'
print(f"{'Python'!a}") # 'Python' — ASCII puro, sem mudança
Debug com = (Python 3.8+)
Uma das adições mais práticas ao Python 3.8 foi o suporte ao = nas f-strings para debug:
x = 42
lista = [1, 2, 3]
nome = "Maria"
# = imprime o nome da expressão e seu valor
print(f"{x = }") # x = 42
print(f"{lista = }") # lista = [1, 2, 3]
print(f"{nome = }") # nome = 'Maria'
print(f"{x * 2 = }") # x * 2 = 84
print(f"{len(lista) = }") # len(lista) = 3
# Combina com format spec
pi = 3.14159265358979
print(f"{pi = :.4f}") # pi = 3.1416
# Muito útil para debug rápido — substitui print("x =", x)
def calcular(a, b):
resultado = a ** 2 + b ** 2
print(f"{a = }, {b = }, {resultado = }")
return resultado
calcular(3, 4) # a = 3, b = 4, resultado = 25
F-strings multilinha
nome = "Carlos"
produto = "Notebook Pro"
preco = 4_999.90
quantidade = 2
# Usando parênteses para quebrar em múltiplas linhas
mensagem = (
f"Olá, {nome}!\n"
f"Produto: {produto}\n"
f"Quantidade: {quantidade}\n"
f"Total: R$ {preco * quantidade:,.2f}"
)
print(mensagem)
# Com triple quotes (preserva quebras de linha literais)
relatorio = f"""
Relatório de Compra
===================
Cliente: {nome:<20}
Produto: {produto:<20}
Valor unit: R$ {preco:>10,.2f}
Qtd: {quantidade:>10}
Total: R$ {preco * quantidade:>10,.2f}
"""
print(relatorio)
F-strings com dicionários e objetos
from dataclasses import dataclass
from datetime import date
@dataclass
class Produto:
nome: str
preco: float
categoria: str
disponivel: bool = True
p = Produto("Café Premium", 28.90, "Bebidas")
# Acessando atributos diretamente
print(f"{p.nome}: R$ {p.preco:.2f}")
print(f"Disponível: {'Sim' if p.disponivel else 'Não'}")
# Com dicionários — aspas dentro das f-strings
config = {'host': 'localhost', 'porta': 5432}
print(f"Conectando em {config['host']}:{config['porta']}")
# Python 3.12+ permite aspas aninhadas sem problemas
# print(f"{'aspas "aninhadas" funcionam'}") # válido no 3.12+
# Formatando listas e objetos complexos
import json
dados = {'usuarios': ['Ana', 'Bruno'], 'total': 2}
print(f"JSON: {json.dumps(dados, ensure_ascii=False)}")
Performance: f-strings vs outras abordagens
import timeit
nome = "Maria"
idade = 30
preco = 1234.56
n = 1_000_000
# Comparação de performance
t_percent = timeit.timeit(lambda: "Nome: %s, Idade: %d" % (nome, idade), number=n)
t_format = timeit.timeit(lambda: "Nome: {}, Idade: {}".format(nome, idade), number=n)
t_fstring = timeit.timeit(lambda: f"Nome: {nome}, Idade: {idade}", number=n)
t_concat = timeit.timeit(lambda: "Nome: " + nome + ", Idade: " + str(idade), number=n)
print(f"% formatting: {t_percent:.3f}s") # ~0.20s
print(f".format(): {t_format:.3f}s") # ~0.22s
print(f"f-string: {t_fstring:.3f}s") # ~0.10s (2x mais rápido)
print(f"concatenação: {t_concat:.3f}s") # ~0.15s
# F-strings são geralmente 2x mais rápidas que .format()
# O ganho é mais expressivo com muitas variáveis ou em loops críticos
F-strings vs Template strings para segurança
from string import Template
# Template strings são mais seguras para input do usuário
# porque não executam código arbitrário
# PERIGO: nunca use f-strings com input do usuário em contextos sensíveis
# user_input = "'; DROP TABLE users; --"
# query = f"SELECT * FROM users WHERE nome = '{user_input}'" # SQL injection!
# Template é seguro para substituição simples de variáveis
template = Template("Olá, $nome! Seu saldo é $$${saldo:.2f}")
resultado = template.substitute(nome="Ana", saldo=150.0)
print(resultado) # Olá, Ana! Seu saldo é $150.00
# Template não executa código — apenas substitui variáveis nomeadas
# Útil para: templates de email, mensagens configuráveis por usuários,
# sistemas de internacionalização (i18n), arquivos de configuração
# Para queries de banco — use sempre parâmetros, nunca formatação de string
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
# Correto — parâmetros parametrizados
cursor.execute("SELECT * FROM tabela WHERE nome = ?", (nome,))
Python 3.12: melhorias nas f-strings
O Python 3.12 (PEP 701) reescreveu o parser de f-strings, eliminando várias limitações anteriores:
# Python 3.12+: aspas aninhadas do mesmo tipo
nome = "Ana"
print(f"{'Olá, ' + nome + '!'}") # Funcionava antes
print(f"{"Olá, " + nome + "!"}") # NOVO no 3.12 — mesmas aspas!
# Backslashes dentro das expressões (antes proibido)
nomes = ["Ana", "Bruno", "Carla"]
# Antes (3.11 e anterior) — precisava de variável auxiliar
sep = '\n'
print(f"{sep.join(nomes)}")
# Python 3.12 — backslash direto na expressão
print(f"{'\n'.join(nomes)}") # funciona!
# Comentários dentro das expressões
resultado = f"""
{
soma := sum(range(10)), # soma dos primeiros 10 números
soma # usa o resultado
}
"""
# F-strings multilinha com expressões complexas ficam mais limpas
dados = [1, 2, 3, 4, 5]
print(f"""
Soma: {sum(dados)}
Média: {sum(dados) / len(dados):.2f}
Máximo: {max(dados)}
Mínimo: {min(dados)}
""")
Erros comuns
# Erro 1: backslash dentro de {} (Python < 3.12)
nomes = ['Ana', 'Bruno']
# print(f"{'\n'.join(nomes)}") # SyntaxError em Python < 3.12
# Solução:
separador = '\n'
print(f"{separador.join(nomes)}")
# Erro 2: chaves literais — use {{ e }}
print(f"Dicionário: {{'chave': 'valor'}}") # {chave: valor}
# Erro 3: f-strings não são avaliadas com segurança em runtime
# Nunca construa f-strings a partir de input do usuário
template_usuario = "f'Olá, {nome}!'" # string, não f-string
# eval(template_usuario) # NUNCA faça isso — executa código arbitrário
# Erro 4: f-strings de múltiplas linhas sem parênteses
# mensagem = f"linha1" # concatenação implícita NÃO funciona com f-strings
# f"linha2"
# Correto:
mensagem = (f"linha1"
f"linha2") # OK — parênteses permitem quebra de linha
Boas práticas
- Use f-strings como método padrão de formatação em código novo — são mais rápidas e legíveis.
- Aproveite o
=para debug temporário em vez de escreverprint("variavel =", variavel). - Use
!rao exibir strings em contextos de debug para ver os caracteres de escape. - Para templates configuráveis por usuários ou internacionalização, prefira
string.Template. - Nunca construa queries SQL, HTML ou comandos de sistema com f-strings usando input do usuário — use parâmetros do driver de banco de dados ou escaping adequado.
- Em Python 3.12+, aproveite as aspas aninhadas para expressões mais naturais.
Termos Relacionados
- Python — A linguagem de programação
- Type Hints — Tipagem estática em Python