É possível fazer formatação parcial de sequência com os métodos avançados de formatação de sequência, semelhante à safe_substitute()
função do modelo de sequência ?
Por exemplo:
s = '{foo} {bar}'
s.format(foo='FOO') #Problem: raises KeyError 'bar'
python
string-formatting
P3trus
fonte
fonte
{bar:1.2f}
__missing__()
, retorne uma instância de uma classe personalizada substituindo de__format__()
forma a retornar o espaço reservado original, incluindo a especificação de formato. Prova de conceito: ideone.com/xykV7RSe você sabe em que ordem está formatando as coisas:
Use-o assim:
Você não pode especificar
foo
ebar
ao mesmo tempo - você deve fazer isso sequencialmente.fonte
s.format(foo='FOO',bar='BAR')
então ainda recebi'FOO {bar}'
, não importa o quê. Você poderia esclarecer isso?Você pode usar a
partial
função dafunctools
qual é curta, mais legível e também descreve a intenção do codificador:fonte
python from functool import partial s = "{foo} {bar}".format s_foo = partial(s, foo="FOO") print(s_foo(bar="BAR")) # FOO BAR print(s(foo="FOO", bar="BAR")) # FOO BAR
partial()
não vai me ajudar se eu precisar fazer algum processamento com a string parcialmente formatada (ou seja"FOO {bar}"
)."{foo} {{bar}}".format(foo="{bar}").format(bar="123")
dos outros exemplos. Eu esperaria,"{bar} 123"
mas eles produzem"123 123"
.Essa limitação
.format()
- a incapacidade de fazer substituições parciais - está me incomodando.Depois de avaliar a criação de uma
Formatter
classe personalizada, conforme descrito em muitas respostas aqui, e mesmo considerando o uso de pacotes de terceiros, como lazy_format , descobri uma solução embutida muito mais simples: Cadeias de modeloEle fornece funcionalidade semelhante, mas também fornece um
safe_substitute()
método completo de substituição parcial . As strings do modelo precisam ter um$
prefixo (o que é um pouco estranho - mas a solução geral é melhor).Formou um invólucro de conveniência com base nisso:
Da mesma forma, um invólucro baseado na resposta de Sven, que usa a formatação padrão de string:
fonte
Não tenho certeza se isso está ok como uma solução rápida, mas que tal
? :)
fonte
Se você definir o seu
Formatter
que substitui oget_value
método, poderá usá-lo para mapear nomes de campos indefinidos para o que quiser:http://docs.python.org/library/string.html#string.Formatter.get_value
Por exemplo, você pode mapear
bar
para"{bar}"
sebar
não estiver nos kwargs.No entanto, isso requer o uso do
format()
método do objeto Formatter, não oformat()
método da string .fonte
Experimente isso.
fonte
{{
e}}
é uma maneira de escapar das marcas de formatação, portantoformat()
, não realiza substituição e substitui{{
e}}
por{
e}
, respectivamente.{{ }}
funciona apenas para um formato; se você precisar aplicar mais, precisará adicionar mais{}
. ex.'fd:{uid}:{{topic_id}}'.format(uid=123).format(a=1)
retornará erro, pois o segundo formato não está fornecendo otopic_id
valor.Graças ao comentário de Amber , eu vim com isso:
fonte
{field!s: >4}
Torna-se{field}
Para mim, isso foi bom o suficiente:
fonte
Todas as soluções que encontrei pareciam ter problemas com opções de especificação ou conversão mais avançadas. @ Do SvenMarnach FormatPlaceholder é maravilhosamente inteligente, mas ele não funciona corretamente com a coerção (por exemplo
{a!s:>2s}
), porque ele chama o__str__
método (neste exemplo) em vez de__format__
e você perder qualquer formatação adicional.Aqui está o que eu acabei e algumas de suas principais características:
str.format
(não apenas um mapeamento){k!s}
{!r}
{k:>{size}}
{k.foo}
{k[0]}
{k!s:>{size}}
Descobri os problemas com as várias implementações depois de escrever alguns testes sobre como eu queria que esse método se comportasse. Eles estão abaixo se alguém os achar perspicazes.
fonte
Minha sugestão seria a seguinte (testada com Python3.6):
Atualização: Uma maneira ainda mais elegante (subclassificação
dict
e sobrecarga__missing__(self, key)
) é mostrada aqui: https://stackoverflow.com/a/17215533/333403fonte
Supondo que você não use a string até que ela esteja completamente preenchida, você pode fazer algo parecido com esta classe:
Exemplo:
fonte
Há mais uma maneira de conseguir isso, ou seja, usando
format
e%
substituindo variáveis. Por exemplo:fonte
Uma solução muito feia, mas a mais simples, para mim, é:
Dessa forma, você ainda pode usar
tmpl
como modelo regular e executar a formatação parcial somente quando necessário. Acho esse problema trivial demais para usar uma solução de exagero como a de Mohan Raj.fonte
Depois de testar as soluções mais promissoras daqui e dali , percebi que nenhuma delas realmente atendia aos seguintes requisitos:
str.format_map()
para o modelo;Então, eu escrevi minha própria solução, que atende aos requisitos acima. ( EDIT : agora a versão do @SvenMarnach - conforme relatado nesta resposta - parece lidar com os casos de canto que eu precisava).
Basicamente, acabei analisando a sequência do modelo, encontrando
{.*?}
grupos aninhados correspondentes (usando umafind_all()
função auxiliar) e construindo a sequência formatada de forma progressiva e direta usandostr.format_map()
enquanto captava qualquer potencialKeyError
.(Este código também está disponível no FlyingCircus - AVISO LEGAL: Eu sou o principal autor dele.)
O uso para esse código seria:
Vamos comparar isso com a minha solução favorita (por @SvenMarnach, que gentilmente compartilhou seu código aqui e ali ):
Aqui estão alguns testes:
e o código para fazê-lo funcionar:
resultando em:
como você pode ver, a versão atualizada agora parece lidar bem com os casos de canto em que a versão anterior costumava falhar.
Timewise, eles estão dentro de aprox. 50% um do outro, dependendo do
text
formato real (e provavelmente do formato realsource
), massafe_format_map()
parece ter uma vantagem na maioria dos testes que realizei (o que eles significam, é claro):fonte
{d[x]}
não é uma string de formato válida, pelo que sei.field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
doisstr.format()
e ostr.format_map()
entendem. Eu diria que há evidências suficientes para que essa seja uma sequência de formato válida.str.format()
com um índice não inteiro entre colchetes? Só posso fazer com que índices inteiros funcionem.a = dict(b='YAY!'); '{a[b]}'.format_map(dict(a=a))
leva você `` YAY! ''a[b]
no código Python, mas na verdade éa["b"]
obrigado!Se você deseja descompactar um dicionário para transmitir argumentos
format
, como nesta pergunta relacionada , use o seguinte método.Primeiro, assuma que a string
s
é a mesma que nesta pergunta:e os valores são fornecidos pelo seguinte dicionário:
Claramente, isso não vai funcionar:
No entanto, você pode primeiro obter um
set
de todos os argumentos nomeadoss
e criar um dicionário que mapeie o argumento para si mesmo envolto em chaves:Agora use o
args
dicionário para preencher as chaves ausentesreplacements
. Para python 3.5+, você pode fazer isso em uma única expressão :Para versões mais antigas do python, você pode chamar
update
:fonte
Eu gosto da resposta do @ sven-marnach. Minha resposta é simplesmente uma versão estendida. Permite formatação sem palavra-chave e ignora chaves extras. Aqui estão exemplos de uso (o nome de uma função é uma referência à formatação da string f do python 3.6):
E aqui está o meu código:
fonte
Se você está fazendo um monte de modelagem e descobrindo que a funcionalidade de modelagem de string incorporada do Python é insuficiente ou desajeitada, veja o Jinja2 .
Dos documentos:
fonte
Lendo o comentário de @Sam Bourne, modifiquei o código de @ SvenMarnach para funcionar corretamente com coerção (como
{a!s:>2s}
) sem escrever um analisador personalizado. A idéia básica não é converter em seqüências de caracteres, mas concatenar chaves ausentes com tags de coerção.Use (por exemplo) assim
Os testes a seguir (inspirados nos testes do @ norok2) verificam a saída do tradicional
format_map
e umsafe_format_map
baseados na classe acima em dois casos: fornecendo palavras-chave corretas ou sem elas.Quais saídas
fonte
Você pode envolvê-lo em uma função que aceita argumentos padrão:
fonte