Voltar ao Glossario
Glossario Python

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 escrever print("variavel =", variavel).
  • Use !r ao 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