Percursos
/
Python
Python
/
Programa
/
Formatação de strings
Fo

Formatação de strings em Python

1 exercício

Sobre Formatação de strings

Formatação de strings em Python

A formatação de strings é o processo de converter valores em strings e inseri-los num modelo de string. O Zen of Python afirma que deve haver "uma forma óbvia de fazer algo em Python". Mas, quando se trata de formatação de strings, as coisas são um pouco... menos zen.

Pode ser surpreendente descobrir que existem quatro formas principais de fazer formatação de strings em Python, cada uma para um cenário diferente. Parte disto deve-se ao longo historial do Python, e outra parte a considerações como a internacionalização ou a sanitização de dados de entrada. Vamos começar pelas adições mais recentes à caixa de ferramentas de formatação de strings e recuar até à formatação "old style" ou "estilo printf()".

Interpolação literal de strings: a f-string

Introduzidas no Python 3.6, as f-strings (abreviatura de "formatted strings") ou interpolação literal de strings são uma forma rápida e eficiente de avaliar (e formatar) expressões e strings para o tipo str, usando o prefixo f (ou F) antes das aspas (assim: f'{object}').

As f-strings podem ser usadas com todos os tipos de aspas delimitadoras, como as de uma linha (' ou ") e as de várias linhas (''' ou """). Quaisquer variáveis, expressões ou outros tipos colocados dentro das {} são primeiro avaliados, depois convertidos numa str e, por fim, concatenados com as strs que estiverem fora das chavetas.

Neste exemplo, inserimos dois valores de variáveis numa frase (uma str e um float):

>>> name = 'eighth'
>>> value = 1/8

# The f-string, using the two values.
# The .2f format code truncates, so the value displays as 0.12.
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.'

As expressões avaliadas podem ser quase tudo. Algumas das (vastas) possibilidades que podem ser avaliadas: strs, números, variáveis, expressões aritméticas, expressões condicionais, tipos incorporados, slices, funções, lambdas, compreensões ou quaisquer objetos com os métodos __str__ ou __repr__ definidos.

Do simples ao complexo:

Inserir uma variável: a utilização mais simples de uma f-string é colocar uma variável diretamente na string.

# Assigning a variable.
>>> name = "World"

# Inserting that variable.
>>> f'Hello, {name}!'
'Hello, World!'

Expressões dentro de {}: qualquer expressão Python válida pode ser avaliada dentro das chavetas. Repara que usar aspas duplas dentro de uma f-string delimitada por aspas simples (ou vice-versa) evita a necessidade de sequências de escape:

# A dictionary of key:value pairs.
>>> waves = {'water': 1, 'light': 3, 'sound': 5}

# Inserting the whole dict.
>>> f'Wave ranks: {waves}'
"Wave ranks: {'water': 1, 'light': 3, 'sound': 5}"

# An expression can be evaluated inline:
>>> f"Tenfold the value of 'light' is {waves['light'] * 10}."
"Tenfold the value of 'light' is 30."

# A method call can also be evaluated inline:
>>> f'{"hello world!".title()} is a classic greeting.'
'Hello World! is a classic greeting.'

# An f-string can be nested inside another f-string:
>>> f"{f'hello world!'.title()} is a classic greeting."
'Hello World! is a classic greeting.'

Formatação da saída: a minilinguagem de especificação de formato pode ser usada para controlar o alinhamento, a precisão numérica e muito mais. A especificação de formato fica depois do valor, separada por um :.

# Right-align a value to ten characters, and round it to 3 decimal places.
>>> value = 1 / 7
>>> f'One seventh is {value:10.3f}.'
'One seventh is      0.143.'

# A format specification can be set using variables as well.
>>> padding = 10
>>> precision = 3
>>> f'One seventh is {value:{padding}.{precision}f}.'
'One seventh is      0.143.'

Juntando tudo: variáveis, expressões, chamadas a funções e formatação da saída:

>>> precision = 3
>>> f"{30e8 * 111_000:6.{precision}e}"
'3.330e+14'

>>> verb = 'meet'
>>> the_end = ['end', 'of', 'transmission']
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {30e8 * 111_000:6.{precision}e} light-years."{the_end}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."[\'end\', \'of\', \'transmission\']'

# Did you notice the escaped single-quotes in the previous example?
# Using double quotes instead of single quotes for the f-string means the list's single-quoted strings print cleanly.
>>> f"Have a nice day. {the_end}"
"Have a nice day. ['end', 'of', 'transmission']"

Há duas limitações principais a ter em conta. As expressões de uma f-string não podem ficar vazias. Além disso, antes do Python 3.12, não podiam conter comentários.

>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed

>>> word = 'word'
>>> f"""A comment in a triple quoted f-string: {
    word # I chose a nice variable
}"""
'A comment in a triple quoted f-string: word'
Caution

A interpolação de strings não pode ser usada em conjunto com a GNU gettext API para internacionalização (I18N) e localização (L10N), por isso recomenda-se que uses a classe string.Template ou o método str.format() apresentados abaixo em vez de uma f-string em qualquer cenário de tradução de "envolvimento de strings".

Tem também em conta que usar expressões dentro das chavetas {} da f-string é semelhante a usar eval() ou exec(), por isso não é muito seguro e nunca deve ser usado com dados de entrada do utilizador.

O método str.format()

O método str.format() substitui os marcadores dentro da string por valores passados como argumentos à função. Os marcadores identificam-se por nomes ({price}), números ({0} ou índices) ou até marcadores vazios (posicionais) {}.

Por exemplo:

# A named placeholder and a positional placeholder.
>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
'My text: named placeholder and 12.'

Tal como acontece com as f-strings, o str.format() do Python suporta toda uma série de especificadores de formato da minilinguagem que podem ser usados para alinhar texto, truncar números de vírgula flutuante e muito mais.

O padrão completo de especificação de formato é {[<name>][!<conversion>][:<format_specifier>]}:

  • <name> pode ser um marcador com nome, um número ou ficar vazio.
  • !<conversion> é opcional e deve ser uma destas três conversões: !s para str(), !r para repr() ou !a para ascii(). Por predefinição, usa-se str().
  • :<format_specifier> é opcional e controla a forma como o valor é apresentado. Podes encontrar aqui mais informação sobre as opções possíveis.

Exemplo de conversões para uma letra com diacrítico:

# Fills in the object at index zero, converted to a string.
>>> 'An e with an umlaut: {0!s}'.format('ë')
'An e with an umlaut: ë'


# Fills in the object at index zero, converted to a repr.
>>> 'An e with an umlaut (object representation): {0!r}'.format('ë')
"An e with an umlaut (object representation): 'ë'"


# Fills in the object at index zero, converted to ASCII.
>>> 'An e with an umlaut converted into ASCII: {0!a}'.format('ë')
"An e with an umlaut converted into ASCII: '\xeb'"


# Fills in the object in the first position,
# then fills in the object in the second position formatted as a repr.
>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."

Exemplos de especificadores de formato comuns:

# Integer and binary/hex representations of the same number.
>>> my_num = 42
>>> f"{my_num} in binary is {my_num:b}. In hex, it is {my_num:x}"
"42 in binary is 101010. In hex, it is 2a"

# Alignment: left (<), right (>), and center (^) using up to ten characters total.
>>> f"[{"left":<10}] [{"right":>10}] [{"center":^10}]"
"[left      ] [     right] [  center  ]"

# Float precision and scientific notation (up to three decimal places).
>>> pi = 3.141592653589793
>>> f"Fixed: {pi:.3}  Scientific: {pi:.3e}"
"Fixed: 3.142  Scientific: 3.142e+00"

# Thousands separator and percentage.
>>> balance = 1000
>>> rate = 0.0225
>>> f"Balance: ${balance:,.0f}  Interest rate: {rate:.1%}"
"Balance: $1,000  Interest rate: 2.2%"

# Putting it all together:
>>> items = [("Widget", 1250, 9.991), ("Gadget", 37, 24.503), ("Doohickey", 4, 149.002)]
>>> header = f"{"Item":<12} {"Qty":>6} {"Price":>9}"
>>> print(header)
Item            Qty     Price
>>> for name, qty, price in items:
...     print(f"{name:<12} {qty:>6} {price:>9.2f}")
Widget         1250      9.99
Gadget           37     24.50
Doohickey         4    149.00

Há mais exemplos no final desta documentação.

Formatação com % ou formatação ao estilo printf()

A utilização do operador % para formatação é o método mais antigo de formatação de strings em Python. Vem da linguagem C e permite usar argumentos posicionais para construir uma str.

Este método foi substituído tanto pelas f-strings como pelo str.format(), e é por isso que a formatação com % é apelidada de "Old Style". Ainda se encontra em Python 2 e/ou em código legado. Embora este método funcione no Python 3.x, a formatação com % é normalmente evitada, porque pode ser propensa a erros, é menos eficiente, tem menos opções disponíveis e qualquer desencontro entre marcador e argumento pode gerar uma exceção. Usar o operador % é semelhante a printf(), por isso também é por vezes designada formatação printf.

# Assigning a variable.
>>> name = "Anna-conda"

# Building a string using %.
>>> "The snake's name is %s." % name
"The snake's name is Anna-conda."

No exemplo acima, o operador % substitui o marcador %s pela variável name em tempo de execução. Se quiseres adicionar várias variáveis a uma string, tens de fornecer um tuplo com um objeto por cada marcador, depois do %:

# Assigning variables.
>>> name = "Billy the Kid"
>>> fruit = "grapes"

# Building a string using %.
>>> "Surprisingly, %s's favorite snack was %s." %(name, fruit)
"Surprisingly, Billy the Kid's favorite snack was grapes."

Strings de modelo

string.Template() (não confundir com as t-strings do Python 3.14) é uma classe do módulo string (por oposição ao tipo str incorporado), que faz parte da biblioteca padrão do Python, mas tem de ser importada para ser usada. As strings de modelo suportam substituição com base em $ e são muito mais simples e menos poderosas do que as outras opções aqui referidas. No entanto, podem ser muito úteis para internacionalização complicada ou para sanitizar dados de entrada externos.

O string.Template é considerado mais seguro para dados de entrada de utilizadores não fidedignos, porque impede a avaliação de expressões arbitrárias ou o acesso a atributos de objetos, o que atenua ataques de injeção de string de formato.

>>> from string import Template

>>> name = "Anna-Conda"

# Creating a Template with placeholder text.
>>> template_string = Template("The snake called `$snake_name` has escaped!")

# Calling .substitute() to replace the placeholder with a value.
>>> template_string.substitute(snake_name=name)
'The snake called `Anna-Conda` has escaped!'

Encontras mais informação sobre string.Template na documentação do Python.

Como escolher que método de formatação usar?

Com todas estas opções e minilinguagens, como decides a que deves recorrer quando formatas strings em Python? Aqui ficam algumas orientações rápidas:

  1. As f-strings são as mais recentes e as mais fáceis de ler. Se não precisares de internacionalizar, devem ser o método preferido para Python 3.6+.

  2. O str.format() é versátil, poderoso e compatível tanto com o gnu gettext como com a maioria das versões de Python.

  3. Se precisares de simplicidade, segurança e/ou muita internacionalização, podes usar string.Template() para atenuar riscos quando tiveres de lidar com dados de entrada de utilizadores, e para envolver strings de tradução.

  4. O operador % é geralmente considerado obsoleto para código novo, embora ainda funcione no Python moderno. Deve ser usado sobretudo por compatibilidade com bases de código mais antigas. A formatação com % é mais propensa a erros (e tem menos funcionalidades) do que os outros métodos, e pode causar problemas na apresentação de caracteres não ASCII. Consulta a tua distribuição específica do Python para obteres detalhes de suporte, se pensares usá-lo.

Se quiseres ir mais longe, tudo sobre formatação e Boas práticas de formatação de strings em Python são bons pontos de partida.

Editar via GitHub A ligação abre numa nova janela ou separador