
O Python tem três maneiras de formatar strings, e uma delas é melhor que as outras. Mas não vamos nos antecipar - de que tipo de formatação estamos falando? Toda vez que queremos cumprimentar um usuário pelo nome, precisamos inserir uma sequência com um nome na sequência do modelo. As entradas de log mais úteis também contêm valores variáveis. E aqui está um exemplo:
integer = 42 string = 'FORTY_TWO' print('string number %s, or simply %d' % (string, integer)) print('string number {}, or simply {}'.format(string, integer)) print(f'string number {string}, or simply {integer}')
O primeiro método, formatado com o operador%, veio no Python do C - imita a função printf. Esse método foi o primeiro no python e continua sendo o único (discutido no artigo) no Python versão 2.5 e abaixo.
A segunda maneira é o método str.format, que pertence à classe de string interna. Ele veio com o Python 3.0 e foi portado para a versão 2.6. Este método foi
recomendado por ter uma sintaxe mais rica.
O terceiro método, f-string, apareceu no Python versão 3.6. Conforme explicado no
PEP-0498 , a criação de uma nova maneira de formatar seqüências de caracteres foi motivada pelas deficiências dos métodos existentes, que os autores caracterizam como propensos a erros, não são flexíveis o suficiente e não são elegantes:
Esse PEP é impulsionado pelo desejo de ter uma maneira mais simples de formatar seqüências de caracteres em Python. As formas de formatação existentes são propensas a erros, inflexíveis ou complicadas.
Portanto, temos três maneiras de resolver um problema. Mas talvez isso seja uma questão de gosto e preferência pessoal? Talvez, mas o estilo do seu código (especialmente o código em um projeto com um grande número de participantes) se beneficiará definitivamente da uniformidade. Na melhor das hipóteses, você deve usar um método de formatação de seqüências de caracteres, e a leitura do código será mais fácil. Mas qual método escolher? E existe uma diferença no desempenho do código?
Vamos tentar responder à pergunta sobre desempenho experimentalmente:
import timeit setup = """ integer = 42 string = 'FORTY_TWO' """.strip() percent_stmt ="'Number %s or simply %d' % (string, integer)" call_stmt = "'Number {} or simply {}'.format(string, integer)" fstr_stmt = """f'Number {string} or simply {integer}'""" def time(stmt): return f"{timeit.timeit(stmt, setup, number=int(1e7)):.3f}" print(f"Timing percent formating: | {time(percent_stmt)}") print(f"Timing call formating: | {time(call_stmt)}") print(f"Timing f-string formating: | {time(fstr_stmt)}")
Resultados no MacBook com Python 3.7:
Timing percent formating: | 2.025 Timing call formating: | 2.943 Timing f-string formating: | 1.348
A diferença é significativa. Então agora, execute a pesquisa regex em ".format" e reescreva centenas de expressões? Em princípio, a tarefa é simples, mas demorada. Mais a chance de cometer um erro e colocar um bug no código que estava funcionando anteriormente! Parece haver espaço para automação. De fato, existem bibliotecas que podem converter a maioria das expressões em strings:
flynt ,
pyupgrade .
Flynt é fácil de usar. Por exemplo, execute a conversão no código-fonte do balão:
38f9d3a65222:~ ikkamens$ git clone https://github.com/pallets/flask.git Cloning into 'flask'... ... Resolving deltas: 100% (12203/12203), done. 38f9d3a65222:~ ikkamens$ flynt flask Flynt run has finished. Stats: Execution time: 0.623s Files modified: 18 Expressions transformed: 43 Character count reduction: 241 (0.04%) _-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_. Please run your tests before commiting. Report bugs as github issues at: https://github.com/ikamensh/flynt Thank you for using flynt! Fstringify more projects and recommend it to your colleagues! _-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_. 38f9d3a65222:~ ikkamens$
Também é importante destacar a possibilidade de converter expressões que ocupam várias linhas e coletar estatísticas sobre as alterações feitas. O sinalizador --line_length XX define o limite de comprimento da linha após a conversão. Flynt permite chamar pyupgrade com o sinalizador --upgrade.
O Pyupgrade inclui mais funcionalidades e pode limpar seu código de muitos artefatos do Python 2 - como herdar de objetos, especificar nomes de classes em super e
muito mais . O Pyupgrade foi desenvolvido para uso com
pré-confirmação , um utilitário para modificar automaticamente o código antes da confirmação.
É melhor converter a fonte em um gita ou outro controle de versão. Vale a pena executar testes e analisar as alterações você mesmo (usando ambientes git diff ou PyCharm). Enquanto estivermos vivos entre os que se importam, que o código se tornou um par de caracteres mais curto, a conversão proativa também economizará seu tempo. Afinal, mais cedo ou mais tarde alguém começará a fazer com as mãos o que pode ser transformado em um utilitário. As strings F funcionam apenas no Python 3.6+, mas em breve isso não será um problema, já que
outras versões se tornarão obsoletas .
Vale a pena notar que o método .format clássico não funcionará completamente. No caso em que você use o mesmo modelo para criar mensagens com variáveis diferentes em lugares diferentes do código, salve esse modelo em uma variável e use-o - o princípio "Não se repita" é muito mais importante do que ganhar nanossegundos na formatação de uma string.
Conclusões:
Analisamos os três métodos de formatação de strings disponíveis no Python 3.6+, seu breve histórico e comparamos seu desempenho. Também examinamos as ferramentas de código aberto para converter automaticamente código em um novo método para formatar seqüências de caracteres e suas funções adicionais. Não esqueça as coisas simples do seu código e boa sorte!