Python f-strings: Formatando Textos
Na aula Juntar e Repetir Textos, montar a frase "A Ana tem 30 anos" deu trabalho: "A Ana tem " + str(idade) + " anos", cuidando dos espaços e convertendo o número. A f-string resolve isso de um jeito muito mais limpo: você escreve a frase inteira e põe as variáveis entre chaves, no lugar onde elas devem aparecer: f"A Ana tem {idade} anos". E ela faz mais: mostra um preço com duas casas decimais, alinha as colunas de um cardápio, põe o separador de milhar. É o jeito preferido de montar textos no Python de hoje.
- A pôr variáveis, contas e métodos dentro de um texto com
f"…{x}…". - A escolher as casas decimais:
{preco:.2f}. - O separador de milhar (
{x:,.2f}) e como chegar ao jeito brasileiro,1.234,56. - A alinhar textos e números em colunas:
{nome:<10},{preco:>8.2f},{titulo:^20}. - Zeros à esquerda (
007), porcentagem (25.6%) e chaves de verdade no texto ({{ }}). - O
{x=}, que mostra o nome e o valor de uma variável, e as f-strings aninhadas do Python 3.12 em diante. - Os erros reais: o
fesquecido, a chave sem fechar e oUnknown format code 'f'.
A ideia: um formulário com lacunas
Pense num formulário impresso: "Eu, ________, com ____ anos, declaro…". O texto já está pronto; só faltam as lacunas, que cada pessoa preenche com os seus dados. A f-string é esse formulário. As chaves { } são as lacunas, e dentro delas você diz o que vai ali: o Python preenche na hora de criar o texto.
O "f" vem de formatted, "formatado". O nome oficial é "texto formatado literal" (formatted string literal), mas todo mundo diz f-string.
1. A primeira f-string
nome = "Ana"
idade = 30
print(f"Olá, {nome}!")
print(f"A {nome} tem {idade} anos.")
print(f"Daqui a 5 anos, terá {idade + 5}.")
print(f"Em maiúsculas: {nome.upper()}")
- f
- A letra
fcolada antes das aspas transforma o texto numa f-string. Sem ela, as chaves são só chaves. - "Olá,
- O texto fixo, escrito normalmente.
- {nome}
- A lacuna: o Python troca
{nome}pelo valor da variávelnome. - {idade}
- Um número. A f-string converte sozinha para texto: nada de
str(). - {idade + 5}
- Dentro das chaves vale qualquer expressão: uma conta, um método, uma função. O Python calcula e põe o resultado.
$ python3 ola.py Olá, Ana! A Ana tem 30 anos. Daqui a 5 anos, terá 35. Em maiúsculas: ANA
Repare como os espaços ficam naturais: você escreve a frase como ela é, e não precisa lembrar de " " entre os pedaços. E o número 30 entrou no texto sem str() e sem TypeError.
Missão: reescreva o print com uma f-string, sem + e sem str(). A saída deve continuar A Ana tem 30 anos.
idade = 30
print("A Ana tem " + str(idade) + " anos.")
idade = 30
print(f"A Ana tem {idade} anos.")
2. Casas decimais: {preco:.2f}
Depois do nome, dentro das chaves, você pode pôr dois-pontos e um "pedido de formato". O mais usado de todos é o das casas decimais:
preco = 12.5
media = 7.66666
print(f"{preco}")
print(f"{preco:.2f}")
print(f"{media:.2f}")
print(f"{media:.1f}")
print(f"{media:.0f}")
print(f"R$ {preco * 3:.2f}")
$ python3 casas.py 12.5 12.50 7.67 7.7 8 R$ 37.50
- preco
- O valor.
- :
- "Agora vem o formato."
- .2
- Duas casas depois do ponto.
- f
- De fixed point, "ponto fixo": mostre como número com casas decimais. (Este
fnão tem nada a ver com ofantes das aspas.)
12.5com.2fvirou12.50: completou com zero. É o jeito certo de mostrar dinheiro.7.66666com.2fvirou7.67: arredondou, não cortou. Com.1f,7.7; com.0f,8.- A expressão e o formato andam juntos:
{preco * 3:.2f}calcula e formata. - A variável não muda:
precocontinua valendo12.5. O formato vale só para o texto que está sendo montado.
Quando o número fica exatamente no meio, o Python arredonda para o lado par: f"{2.5:.0f}" dá 2, e f"{3.5:.0f}" dá 4. É a regra do "arredondamento bancário", que evita que os arredondamentos puxem sempre para cima. Para dinheiro com duas casas, isso quase nunca aparece.
Missão: o preço do café saiu como R$ 4.5. Faça sair com duas casas decimais: R$ 4.50.
preco = 4.5
print(f"Café: R$ {preco}")
preco = 4.5
print(f"Café: R$ {preco:.2f}")
3. Separador de milhar, e o jeito brasileiro
Números grandes ficam difíceis de ler: 1234567.891. Uma vírgula (ou um sublinhado) no formato separa os milhares:
salario = 1234567.891
print(f"{salario:,.2f}")
print(f"{salario:_.2f}")
print(f"{1500000:,}")
$ python3 milhar.py 1,234,567.89 1_234_567.89 1,500,000
Mas repare: saiu no jeito americano, com vírgula nos milhares e ponto nos decimais. No Brasil é o contrário: 1.234.567,89. O formato da f-string não tem uma opção "brasileira", então o truque mais usado é trocar os sinais depois, com o replace() da aula Métodos de Texto:
salario = 1234567.891
americano = f"{salario:,.2f}"
brasileiro = americano.replace(",", "X").replace(".", ",").replace("X", ".")
print(americano)
print(brasileiro)
print(f"R$ {brasileiro}")
$ python3 brasileiro.py 1,234,567.89 1.234.567,89 R$ 1.234.567,89
.replace(",", "X"): as vírgulas viram umXprovisório:1X234X567.89..replace(".", ","): o ponto decimal vira vírgula:1X234X567,89..replace("X", "."): osXviram pontos:1.234.567,89.
Por que o X? Se você trocasse direto as vírgulas por pontos, depois não saberia mais quais pontos eram os decimais. O X guarda o lugar, como quando você troca o conteúdo de dois copos usando um terceiro.
locale?
O Python tem um módulo, o locale, que formata números do jeito de cada país. Ele depende de como o sistema está configurado (o "pt_BR" precisa estar instalado na máquina), e por isso pode funcionar num computador e falhar em outro. O truque do replace() funciona em qualquer lugar.
4. Alinhando: <, > e ^
Um número logo depois dos dois-pontos diz a largura: quantos caracteres o pedaço deve ocupar, completando com espaços. Um sinal antes dele diz para que lado encostar. Os colchetes no exemplo mostram onde o pedaço começa e termina:
print(f"[{'pão':<10}]")
print(f"[{'pão':>10}]")
print(f"[{'pão':^10}]")
print(f"[{'pão':*^10}]")
print(f"[{'pão':.<10}]")
$ python3 alinhar.py [pão ] [ pão] [ pão ] [***pão****] [pão.......]
| Formato | O que faz | Como lembrar |
|---|---|---|
:<10 | Ocupa 10, encostado à esquerda | A ponta da seta aponta para onde o texto vai |
:>10 | Ocupa 10, encostado à direita | Bom para números e preços |
:^10 | Ocupa 10, centralizado | O ^ é um "telhadinho" no meio |
:*^10 | Centralizado, completando com * | O caractere antes do sinal é o "enchimento" |
Repare nas aspas: dentro de uma f-string com aspas duplas, o texto 'pão' foi escrito com aspas simples. (Desde o Python 3.12, aspas duplas também funcionariam; veja a seção 7.)
Com largura e casas decimais juntas, a Ana monta o cardápio da padaria em colunas. Texto à esquerda, preço à direita:
print(f"{'Produto':<15}{'Preço':>8}")
print(f"{'Pão francês':<15}{0.8:>8.2f}")
print(f"{'Bolo de fubá':<15}{25:>8.2f}")
print(f"{'Café':<15}{4.5:>8.2f}")
$ python3 cardapio.py Produto Preço Pão francês 0.80 Bolo de fubá 25.00 Café 4.50
{0.8:>8.2f} se lê: "8 de largura, encostado à direita, com 2 casas decimais". Assim os pontos decimais ficam todos um embaixo do outro. Os números já se alinham à direita sozinhos, então {0.8:8.2f} daria o mesmo; o > deixa a intenção clara.
Experimente: acrescente uma linha para o "Sonho", de 6 reais, e mude as larguras (15 e 8) para ver o que acontece com as colunas.
print(f"{'Produto':<15}{'Preço':>8}")
print(f"{'Pão francês':<15}{0.8:>8.2f}")
print(f"{'Bolo de fubá':<15}{25:>8.2f}")
5. Zeros, porcentagem e chaves de verdade
pedido = 7
acerto = 0.256
print(f"Pedido nº {pedido:03}")
print(f"Pedido nº {pedido:03d}")
print(f"Acertos: {acerto:.1%}")
print(f"Chaves: {{nome}}")
$ python3 zeros.py
Pedido nº 007
Pedido nº 007
Acertos: 25.6%
Chaves: {nome}
:03: largura 3, completando com zeros à esquerda.:03dé o mesmo, dizendo que é um inteiro (dde "decimal", base 10).:.1%: multiplica por 100, põe o%e uma casa decimal.0.256virou25.6%.{{e}}: para escrever uma chave de verdade numa f-string, dobre-a.
6. {x=}: o nome e o valor, para conferir
Quando um programa não faz o que você espera, é comum espalhar print para ver quanto vale cada variável. Com um = no fim, dentro das chaves, a f-string mostra o nome e o valor de uma vez:
preco = 12.5
quantidade = 3
print(f"{preco=}")
print(f"{quantidade = }")
print(f"{preco * quantidade = }")
print(f"{preco=:.2f}")
$ python3 igual.py preco=12.5 quantidade = 3 preco * quantidade = 37.5 preco=12.50
Os espaços que você põe em volta do = aparecem na saída. Funciona com contas também (a conta aparece escrita, seguida do resultado), e dá para juntar com um formato: {preco=:.2f}. Use enquanto procura um problema, e apague depois; para conferir programas maiores, existe a aula Depurando com pdb.
7. f-strings dentro de f-strings (Python 3.12 em diante)
Desde o Python 3.12, o que está dentro das chaves pode usar as mesmas aspas da f-string de fora, e até outra f-string:
compras = ["pão", "leite", "café"]
print(f"Comprar: {", ".join(compras)}")
nome = "Ana"
print(f"{f"[{nome}]":>12}")
largura = 10
print(f"{'pão':>{largura}}")
$ python3 aninhada.py
Comprar: pão, leite, café
[Ana]
pão
- {", ".join(compras)}
- Aspas duplas dentro de uma f-string de aspas duplas. O Python entende que as aspas de dentro pertencem à expressão entre chaves.
- {f"[{nome}]":>12}
- Uma f-string dentro da outra: a de dentro monta
[Ana]; a de fora alinha esse texto à direita, em 12 caracteres. - {'pão':>{largura}}
- Chaves dentro do formato: a largura vem de uma variável. (Isso funciona em versões bem mais antigas também.)
Essa liberdade com as aspas veio no Python 3.12 (a mudança se chama PEP 701). No 3.11 e anteriores, f"{", ".join(compras)}" dá SyntaxError, e você precisa usar o outro tipo de aspas por dentro: f"{', '.join(compras)}". O guia ensina o 3.14, e o Debian 13 traz o 3.13, ambos depois da mudança. Mas, se o seu código vai rodar em computadores antigos, alternar as aspas é o jeito que funciona em todos. (Não deu para rodar um Python 3.11 no laboratório; o comportamento antigo está descrito conforme a documentação oficial.)
Com t no lugar do f, como em t"Olá, {nome}!", o Python 3.14 cria uma t-string (de template, "modelo"). Ela não vira texto na hora: vira um objeto do tipo string.templatelib.Template, que guarda as partes fixas e os valores separados, para outro código decidir como juntar (por exemplo, protegendo um site contra textos maliciosos). É um recurso para bibliotecas, não para o dia a dia de quem está começando. Mais em Novidades do Python 3.14 e 3.15.
nome = "Ana"
modelo = t"Olá, {nome}!"
print(type(modelo))
$ python3 tstring.py <class 'string.templatelib.Template'>
Formas diferentes de montar o mesmo texto
Você vai encontrar, em código mais antigo, outros dois jeitos de formatar: o método format() e o operador %. Todos dão Café: R$ 4.50 (com preco = 4.5):
| Forma | Exemplo | Quando usar |
|---|---|---|
| f-string | f"Café: R$ {preco:.2f}" | Sempre, em código novo: é a mais clara (desde o Python 3.6) |
format() | "Café: R$ {:.2f}".format(preco) | Quando o modelo do texto é guardado antes, numa variável, e preenchido depois |
% | "Café: R$ %.2f" % preco | Só para ler código antigo |
+ e str() | "Café: R$ " + str(preco) | Para emendar poucos textos, sem formato (e aqui não daria o .50) |
Os formatos depois dos dois-pontos (.2f, >8, ,) são os mesmos na f-string e no format(). A tabela completa está na Referência de Formatação.
Quando dá errado
f
nome = "Ana"
print("Olá, {nome}!")
$ python3 sem-f.py
Olá, {nome}!
Nenhum erro, e a lacuna não foi preenchida: saiu {nome}, com chaves e tudo. Sem o f, é um texto comum, e as chaves são só caracteres. Como consertar: print(f"Olá, {nome}!"), com o f colado nas aspas.
nome = "Ana"
print(f"Olá, {nome")
$ python3 chave-aberta.py
File "/home/ana/chave-aberta.py", line 2
print(f"Olá, {nome")
^
SyntaxError: f-string: expecting '}'
f-string: expecting '}': "na f-string, esperava um }". O ^ aponta a aspa que fechou o texto antes da chave. Não há Traceback: o Python achou o erro só de ler o código. Como consertar: feche a chave, f"Olá, {nome}".
nome = "Ana"
print(f"Olá, {nomee}!")
$ python3 nome-errado.py
Traceback (most recent call last):
File "/home/ana/nome-errado.py", line 2, in <module>
print(f"Olá, {nomee}!")
^^^^^
NameError: name 'nomee' is not defined. Did you mean: 'nome'?
O que está nas chaves é código Python de verdade, e tem as mesmas regras: um nome que não existe dá NameError, com os ^ embaixo dele e a dica Did you mean: 'nome'?. Como consertar: corrija o nome.
Unknown format code 'f'
A Ana lê o preço do teclado e quer mostrar com duas casas:
preco = input("Preço: ")
print(f"R$ {preco:.2f}")
$ python3 formato-texto.py
Preço: 12.5
Traceback (most recent call last):
File "/home/ana/formato-texto.py", line 2, in <module>
print(f"R$ {preco:.2f}")
^^^^^^^^^^^
ValueError: Unknown format code 'f' for object of type 'str'
- ValueError:
- "Erro de valor".
- Unknown format code 'f'
- "Código de formato desconhecido:
f". - for object of type 'str'
- "…para um objeto do tipo
str". O.2fé um formato de número, e oinput()sempre devolve texto:"12.5", com aspas.
Como consertar: converta antes, com float() (aula Conversão de Tipos):
preco = float(input("Preço: "))
print(f"R$ {preco:.2f}")
$ python3 formato-texto2.py Preço: 12.5 R$ 12.50
A Ana quis o separador de milhar e pôs a vírgula no fim:
total = 1234.5
print(f"{total:.2f,}")
$ python3 virgula-errada.py
Traceback (most recent call last):
File "/home/ana/virgula-errada.py", line 2, in <module>
print(f"{total:.2f,}")
^^^^^^^^^^^^
ValueError: Invalid format specifier '.2f,' for object of type 'float'
Invalid format specifier '.2f,': "pedido de formato inválido". As partes do formato têm uma ordem fixa: alinhamento e largura, depois o separador, depois as casas e o tipo. Como consertar: {total:,.2f}, com a vírgula antes do ponto.
Referência rápida
Com x = 3.14159, n = 42 e t = "oi":
| Escrita | O que faz | Resultado |
|---|---|---|
f"{x}" | Põe o valor | 3.14159 |
f"{x:.2f}" | 2 casas decimais | 3.14 |
f"{1234567:,}" | Separador de milhar | 1,234,567 |
f"[{n:>6}]" | Largura 6, à direita | [ 42] |
f"[{t:<6}]" | Largura 6, à esquerda | [oi ] |
f"[{t:^6}]" | Largura 6, centralizado | [ oi ] |
f"{t:*^6}" | Centralizado, com * | **oi** |
f"{n:05}" | Zeros à esquerda | 00042 |
f"{0.5:.0%}" | Porcentagem | 50% |
f"{n=}" | Nome e valor | n=42 |
f"{{ }}" | Chaves de verdade | { } |
| Sintoma | Causa provável |
|---|---|
Saiu {nome} no texto | Faltou o f antes das aspas |
SyntaxError: f-string: expecting '}' | Chave sem fechar |
ValueError: Unknown format code 'f' for object of type 'str' | Formato de número num texto: converta com float() |
ValueError: Invalid format specifier | Partes do formato na ordem errada (é :,.2f) |
1,234.50 no lugar de 1.234,50 | O formato é o americano: troque os sinais com replace() |
Exercícios
1. A letra mágica
Complete para que {nome} seja trocado pelo valor da variável:
2. Duas casas
Complete o formato para mostrar 3.14 a partir de x = 3.14159:
3. O resultado
O que print(f"{2 + 3 = }") mostra?
4. Com preco = 7, o que print(f"R$ {preco:.2f}") mostra?
5. Qual formato encosta o texto à direita, em 10 caracteres?
6. preco = input("Preço: ") e depois f"{preco:.2f}" deu ValueError: Unknown format code 'f' for object of type 'str'. Por quê?
Missão final: o total em reais
Missão: a Ana vende 3 cestas de café da manhã. O preço de cada uma é digitado (aqui, o editor digita 1234.5 por você). O total sai como R$ 3703.5. Faça sair no jeito brasileiro, com separador de milhar e duas casas: Total: R$ 3.703,50.
preco = float(input("Preço da cesta: "))
quantidade = 3
total = preco * quantidade
print(f"Total: R$ {total}")
preco = float(input("Preço da cesta: "))
quantidade = 3
total = preco * quantidade
texto = f"{total:,.2f}".replace(",", "X").replace(".", ",").replace("X", ".")
print(f"Total: R$ {texto}")
Resumo
- Uma f-string tem um
fantes das aspas e lacunas entre chaves:f"Olá, {nome}!". Dentro das chaves vale qualquer expressão, e números entram semstr(). - Depois de dois-pontos vem o formato:
{x:.2f}(casas decimais),{x:,}(milhar),{t:<10}/{t:>10}/{t:^10}(alinhamento),{n:03}(zeros),{p:.1%}(porcentagem). - O formato de milhar é o americano; para o brasileiro, troque os sinais com
replace()(passando por um caractere provisório). {x=}mostra o nome e o valor: ótimo para conferir.- Desde o 3.12, as aspas de dentro podem ser iguais às de fora, e f-strings podem ficar uma dentro da outra.
- Sem o
f, as chaves aparecem no texto; formato de número em texto dáValueError: Unknown format code 'f'.