O Python 2.6 introduziu o str.format()
método com uma sintaxe ligeiramente diferente do %
operador existente . Qual é o melhor e para que situações?
A seguir, use cada método e tenha o mesmo resultado. Qual é a diferença?
#!/usr/bin/python sub1 = "python string!" sub2 = "an arg" a = "i am a %s" % sub1 b = "i am a {0}".format(sub1) c = "with %(kwarg)s!" % {'kwarg':sub2} d = "with {kwarg}!".format(kwarg=sub2) print a # "i am a python string!" print b # "i am a python string!" print c # "with an arg!" print d # "with an arg!"
Além disso, quando ocorre a formatação de string no Python? Por exemplo, se o meu nível de log estiver definido como HIGH, ainda receberei um resultado para executar a
%
operação a seguir ? E se sim, existe uma maneira de evitar isso?log.debug("some debug info: %s" % some_info)
python
performance
logging
string-formatting
f-string
NorthIsUp
fonte
fonte
%
estilo antigo com mais frequência, porque se você não precisar dos recursos aprimorados doformat()
estilo, o%
estilo geralmente será muito mais conveniente.format()
estilo de formatação eo mais velho%
estilo de formatação baseada .Respostas:
Responder à sua primeira pergunta ...
.format
parece mais sofisticado de várias maneiras. Uma coisa irritante%
também é como ela pode pegar uma variável ou uma tupla. Você acha que o seguinte sempre funcionaria:no entanto, se
name
acontecer(1, 2, 3)
, lançará aTypeError
. Para garantir que sempre seja impresso, você precisará fazero que é feio.
.format
não tem esses problemas. Também no segundo exemplo que você deu, o.format
exemplo é muito mais limpo.Por que você não o usaria?
Para responder à sua segunda pergunta, a formatação da string ocorre ao mesmo tempo que qualquer outra operação - quando a expressão de formatação da string é avaliada. E Python, não sendo uma linguagem lenta, avalia expressões antes de chamar funções, portanto, no seu
log.debug
exemplo, a expressão"some debug info: %s"%some_info
será avaliada primeiro como, por exemplo"some debug info: roflcopters are active"
, a sequência que será transmitidalog.debug()
.fonte
"%(a)s, %(a)s" % {'a':'test'}
log.debug("something: %s" % x)
mas não para.log.debug("something: %s", x)
A formatação da string será tratada no método e você não obterá o desempenho atingido se não for registrado. Como sempre, Python antecipa suas necessidades =)'{0}, {0}'.format('test')
.man sprintf
e aprender sobre a$
notação dentro%
espaços reservadosprintf("%2$d", 1, 3)
para imprimir "3", isso é especificado no POSIX, não no C99. A própria página do manual que você referenciou observa: "O padrão C99 não inclui o estilo usando '$' ...".Algo que o operador do módulo (%) não pode fazer:
resultado
Muito útil.
Outro ponto:
format()
sendo uma função, pode ser usado como argumento em outras funções:Resulta em:
fonte
map
tão facilmente quanto o formato.map('some_format_string_%s'.__mod__, some_iterable)
printf("%2$s %1$s\n", "One", "Two");
compilado comgcc -std=c99 test.c -o test
, a saída éTwo One
. Mas permaneço corrigido: na verdade, é uma extensão POSIX e não C. Não consigo encontrá-la novamente no padrão C / C ++, onde pensei ter visto. O código funciona mesmo com o sinalizador 'c90' std.sprintf
página de manual . Isso não lista, mas permite que as bibliotecas implementem um superconjunto. Meu argumento original ainda é válido, substituindoC
porPosix
%
para reordenar espaços reservados. Eu ainda gostaria de não excluir esse primeiro comentário por uma questão de consistência aqui. Peço desculpas por ter desabafado minha raiva aqui. É direcionado contra a afirmação frequentemente feita de que a sintaxe antiga por si só não permitiria isso. Em vez de criar uma sintaxe completamente nova, poderíamos ter introduzido as extensões stix Posix. Nós poderíamos ter os dois.Supondo que você esteja usando o
logging
módulo Python , você pode passar os argumentos de formatação de string como argumentos para o.debug()
método, em vez de fazer a formatação:que evita a formatação, a menos que o criador de logs realmente registre algo.
fonte
log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry'))
No entanto, você não pode usar a nova.format()
sintaxe de estilo aqui, nem mesmo no Python 3.3, o que é uma pena.A partir do Python 3.6 (2016), você pode usar as strings f para substituir variáveis:
Anote o
f"
prefixo. Se você tentar isso no Python 3.5 ou anterior, obterá umSyntaxError
.Consulte https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings
fonte
O PEP 3101 propõe a substituição do
%
operador pela nova e avançada formatação de string no Python 3, onde seria o padrão.fonte
.format
não substituirá a%
formatação da string.Mas tenha cuidado, só agora eu descobri um problema ao tentar substituir todos
%
com.format
no código existente:'{}'.format(unicode_string)
vai tentar UNICODE_STRING codificar e provavelmente irá falhar.Basta olhar para este log de sessão interativa do Python:
s
é apenas uma string (chamada 'matriz de bytes' em Python3) eu
é uma string Unicode (chamada de 'string' em Python3):Quando você fornece um objeto Unicode como parâmetro ao
%
operador, ele produz uma cadeia Unicode, mesmo que a cadeia original não fosse Unicode:mas a
.format
função gerará "UnicodeEncodeError":e só funcionará com um argumento Unicode se a cadeia original for Unicode.
ou se a sequência de argumentos puder ser convertida em uma sequência (chamada de 'matriz de bytes')
fonte
format
método são realmente necessário ...%
interpolação de cordas vá embora."p1=%s p2=%d" % "abc", 2
ou"p1=%s p2=%s" % (tuple_p1_p2,)
. Você pode pensar que é culpa do codificador, mas eu acho que é apenas uma sintaxe estranha que parece boa para o script rápido, mas é ruim para o código de produção.%s
,%02d
como"p1=%s p2=%02d".format("abc", 2)
. Eu culpo aqueles que inventaram e aprovaram a formatação do aparelho que precisa de você para escapar deles{{}}
e que parece feio.Ainda outra vantagem
.format
(que não vejo nas respostas): pode levar propriedades de objetos.Ou, como argumento da palavra-chave:
Isso não é possível
%
, tanto quanto eu posso dizer.fonte
'x is {0}, y is {1}'.format(a.x, a.y)
. Só deve ser usado quando aa.x
operação é muito cara.'x is {a.x}, y is {a.y}'.format(a=a)
. Mais legível que os dois exemplos.'x is {a.x}, y is {a.y}'.format(**vars())
'{foo[bar]}'.format(foo={'bar': 'baz'})
.Your order, number {order[number]} was processed at {now:%Y-%m-%d %H:%M:%S}, will be ready at about {order[eta]:%H:%M:%S}
ou o que quiser. Isso é muito mais limpo do que tentar oferecer a mesma funcionalidade com o formatador antigo. Torna as strings de formato fornecidas pelo usuário muito mais poderosas.%
dá um desempenho melhor do queformat
no meu teste.Código do teste:
Python 2.7.2:
Resultado:
Python 3.5.2
Resultado
Parece em Python2, a diferença é pequena, enquanto em Python3,
%
é muito mais rápido queformat
.Obrigado @ Chris Cogdon pelo código de exemplo.
Editar 1:
Testado novamente no Python 3.7.2 em julho de 2019.
Resultado:
Não há muita diferença. Eu acho que o Python está melhorando gradualmente.
Edição 2:
Depois que alguém mencionou a string f do python 3 no comentário, fiz um teste para o seguinte código no python 3.7.2:
Resultado:
Parece que o fio-f ainda é mais lento que,
%
mas melhor queformat
.fonte
str.format
fornece mais funcionalidades (especialmente formatação especializada em tipos, por exemplo'{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())
). O desempenho não pode ser o requisito absoluto de todos os trabalhos. Use a ferramenta certa para o trabalho.%
operador permite reutilizar oprintf
conhecimento; interpolação de dicionário é uma extensão muito simples do princípio.Como descobri hoje, a maneira antiga de formatar strings via
%
não é compatívelDecimal
, o módulo do Python para aritmética de ponto fixo decimal e ponto flutuante, pronto para uso.Exemplo (usando Python 3.3.5):
Resultado:
Certamente pode haver soluções alternativas, mas você ainda pode considerar o uso do
format()
método imediatamente.fonte
str(d)
antes de expandir o parâmetro, enquanto a formatação com estilo antigo provavelmente chamafloat(d)
primeiro.str(d)
retorna"3.12375239e-24"
, não"0.00000000000000000000000312375239000000000000000000"
Se o seu python> = 3.6, o literal formatado em F-string é seu novo amigo.
É mais simples, limpo e com melhor desempenho.
fonte
Como uma observação lateral, você não precisa ter um impacto no desempenho para usar a nova formatação de estilo com o log. Você pode passar qualquer objeto a
logging.debug
,logging.info
etc., que implementa o__str__
método mágico. Quando o módulo de registro decide que deve emitir seu objeto de mensagem (seja ele qual for), ele chamastr(message_object)
antes de fazê-lo. Então você poderia fazer algo assim:Tudo isso está descrito na documentação do Python 3 ( https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). No entanto, ele também funcionará com o Python 2.6 ( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages ).
Uma das vantagens de usar essa técnica, além do fato de ser agnóstico no estilo de formatação, é que ela permite valores preguiçosos, por exemplo, a função
expensive_func
acima. Isso fornece uma alternativa mais elegante aos conselhos dados nos documentos do Python aqui: https://docs.python.org/2.6/library/logging.html#optimization .fonte
format
sem o desempenho atingido - substitui com__str__
precisão o quelogging
foi projetado - reduz a chamada de função para uma única letra (N
) que se parece muito com algumas das maneiras padrão de definir strings - E permite preguiçosos chamada de função. Obrigado! 1logging.Formatter(style='{')
parâmetro?Uma situação em que
%
pode ajudar é quando você está formatando expressões regex. Por exemplo,aumenta
IndexError
. Nesta situação, você pode usar:Isso evita escrever a regex como
'{type_names} [a-z]{{2}}'
. Isso pode ser útil quando você possui duas expressões regulares, em que uma é usada sozinha sem formato, mas a concatenação de ambas é formatada.fonte
'{type_names} [a-z]{{2}}'.format(type_names='triangle|square')
. É como dizer que.format()
pode ajudar ao usar strings que já contêm um caractere de porcentagem. Certo. Você tem que escapar deles então."One situation where % may help is when you are formatting regex expressions."
Especificamente, suponha quea=r"[a-z]{2}"
seja um pedaço de regex que você será usado em duas expressões finais diferentes (por exemplo,c1 = b + a
ec2 = a
). Suponha quec1
precise serformat
editado (por exemplo,b
precisa ser formatado em tempo de execução), masc2
não precisa. Então você precisaa=r"[a-z]{2}"
parac2
ea=r"[a-z]{{2}}"
parac1.format(...)
.Eu acrescentaria que desde a versão 3.6, podemos usar fstrings como o seguinte
Que dão
Tudo é convertido em strings
Resultado:
você pode passar a função, como no método de outros formatos
Dando por exemplo
fonte
Para a versão python> = 3.6 (consulte PEP 498 )
fonte
Comparativo do Python 3.6.7:
Resultado:
fonte
Mas uma coisa é que também se você tiver chaves aninhadas, não funcionará para o formato, mas
%
funcionará.Exemplo:
fonte