Est-il possible d'effectuer un formatage de chaîne partiel avec les méthodes de formatage de chaîne avancées, similaires à la safe_substitute()
fonction de modèle de chaîne ?
Par exemple:
s = '{foo} {bar}'
s.format(foo='FOO') #Problem: raises KeyError 'bar'
python
string-formatting
P3trus
la source
la source
{bar:1.2f}
__missing__()
, retournez une instance d'une classe personnalisée remplaçant__format__()
de manière à renvoyer l'espace réservé d'origine, y compris la spécification de format. Preuve de concept: ideone.com/xykV7RSi vous savez dans quel ordre vous formatez les choses:
Utilisez-le comme ceci:
Vous ne pouvez pas spécifier
foo
etbar
en même temps - vous devez le faire de manière séquentielle.la source
s.format(foo='FOO',bar='BAR')
alors j'ai toujours'FOO {bar}'
, quoi qu'il arrive . Pouvez-vous clarifier cela?Vous pouvez utiliser la
partial
fonction à partir defunctools
laquelle est courte, la plus lisible et décrit également l'intention du codeur:la source
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()
ne va pas m'aider si j'ai besoin de faire un traitement avec la chaîne partiellement formatée (c'est-à-dire"FOO {bar}"
)."{foo} {{bar}}".format(foo="{bar}").format(bar="123")
partir des autres exemples. Je m'attendrais"{bar} 123"
mais ils sortent"123 123"
.Cette limitation de
.format()
- l'incapacité de faire des substitutions partielles - m'a dérangé.Après avoir évalué l'écriture d'une
Formatter
classe personnalisée comme décrit dans de nombreuses réponses ici et même envisagé d'utiliser des packages tiers tels que lazy_format , j'ai découvert une solution intégrée beaucoup plus simple: les chaînes de modèleIl fournit des fonctionnalités similaires mais fournit également une
safe_substitute()
méthode approfondie de substitution partielle . Les chaînes de modèle doivent avoir un$
préfixe (ce qui semble un peu étrange - mais la solution globale, je pense, est meilleure).Formé un emballage pratique basé sur ceci:
De même, un wrapper basé sur la réponse de Sven qui utilise le formatage de chaîne par défaut:
la source
Je ne sais pas si cela est correct comme solution de contournement rapide, mais que diriez-vous
? :)
la source
Si vous définissez le vôtre
Formatter
qui remplace laget_value
méthode, vous pouvez l'utiliser pour mapper des noms de champs non définis à ce que vous voulez:http://docs.python.org/library/string.html#string.Formatter.get_value
Par exemple, vous pouvez mapper
bar
à"{bar}"
sibar
n'est pas dans les kwargs.Cependant, cela nécessite d'utiliser la
format()
méthode de votre objet Formatter, pas laformat()
méthode de la chaîne .la source
Essayez ceci.
la source
{{
et}}
est un moyen d'échapper aux marques de mise en forme, doncformat()
n'effectue pas de substitution et remplace{{
et}}
avec{
et}
, respectivement.{{ }}
ne fonctionne que pour un format, si vous devez en appliquer plus, vous devrez en ajouter plus{}
. ex.'fd:{uid}:{{topic_id}}'.format(uid=123).format(a=1)
renverra une erreur car le second format ne fournit pas latopic_id
valeur.Grâce au commentaire d' Amber , j'ai trouvé ceci:
la source
{field!s: >4}
devient{field}
Pour moi, c'était assez bien:
la source
Toutes les solutions que j'ai trouvées semblaient avoir des problèmes avec des spécifications ou des options de conversion plus avancées. @ SvenMarnach de FormatPlaceholder est merveilleusement intelligent , mais il ne fonctionne pas correctement avec la contrainte (par exemple
{a!s:>2s}
) , car il appelle la__str__
méthode (dans cet exemple) au lieu de__format__
et vous perdez toute mise en forme supplémentaire.Voici ce avec quoi je me suis retrouvé et certaines de ses fonctionnalités clés:
str.format
(pas seulement un mappage){k!s}
{!r}
{k:>{size}}
{k.foo}
{k[0]}
{k!s:>{size}}
J'ai découvert les problèmes avec les différentes implémentations après avoir écrit quelques tests sur la façon dont je voulais que cette méthode se comporte. Ils sont ci-dessous si quelqu'un les trouve perspicaces.
la source
Ma suggestion serait la suivante (testée avec Python3.6):
Mise à jour: Une manière encore plus élégante (sous
dict
-classement et surcharge__missing__(self, key)
) est présentée ici: https://stackoverflow.com/a/17215533/333403la source
En supposant que vous n'utiliserez pas la chaîne tant qu'elle n'est pas complètement remplie, vous pouvez faire quelque chose comme cette classe:
Exemple:
la source
Il existe une autre façon d'y parvenir, c'est-à-dire en utilisant
format
et%
en remplaçant des variables. Par exemple:la source
Une solution très moche mais la plus simple pour moi est de simplement faire:
De cette façon, vous pouvez toujours utiliser
tmpl
comme modèle régulier et effectuer un formatage partiel uniquement lorsque cela est nécessaire. Je trouve ce problème trop trivial pour utiliser une solution exagérée comme celle de Mohan Raj.la source
Après avoir testé les solutions les plus prometteuses ici et là , je me suis rendu compte qu'aucune d'entre elles ne répondait vraiment aux exigences suivantes:
str.format_map()
pour le modèle;J'ai donc écrit ma propre solution, qui satisfait aux exigences ci-dessus. ( EDIT : maintenant la version de @SvenMarnach - comme indiqué dans cette réponse - semble gérer les cas de coin dont j'avais besoin).
Fondamentalement, j'ai fini par analyser la chaîne de modèle, trouver des
{.*?}
groupes imbriqués correspondants (en utilisant unefind_all()
fonction d'assistance) et construire la chaîne formatée progressivement et directement en utilisantstr.format_map()
tout en captant tout potentielKeyError
.(Ce code est également disponible dans FlyingCircus - AVIS DE NON -RESPONSABILITÉ: j'en suis l'auteur principal.)
L'utilisation de ce code serait:
Comparons cela à ma solution préférée (par @SvenMarnach qui a gentiment partagé son code ici et là ):
Voici quelques tests:
et le code pour le faire fonctionner:
résultant en:
comme vous pouvez le voir, la version mise à jour semble maintenant bien gérer les cas de coin où la version antérieure échouait.
Dans le temps, ils sont à env. 50% les uns des autres, selon le
text
format réel (et probablement le réelsource
), maissafe_format_map()
semble avoir un avantage dans la plupart des tests que j'ai effectués (quoi qu'ils signifient, bien sûr):la source
{d[x]}
n'est pas une chaîne de format valide pour autant que je sache.field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
, les deuxstr.format()
et lestr.format_map()
comprennent. Je dirais qu'il y a suffisamment de preuves pour qu'il s'agisse d'une chaîne de format valide.str.format()
avec un index non entier entre crochets? Je ne peux faire fonctionner que les index entiers.a = dict(b='YAY!'); '{a[b]}'.format_map(dict(a=a))
vous obtient `` YAY! ''a[b]
dans le code Python, mais c'est en faita["b"]
Merci!Si vous souhaitez décompresser un dictionnaire auquel passer des arguments
format
, comme dans cette question connexe , vous pouvez utiliser la méthode suivante.Supposons d'abord que la chaîne
s
est la même que dans cette question:et les valeurs sont données par le dictionnaire suivant:
Clairement, cela ne fonctionnera pas:
Cependant, vous pouvez d'abord obtenir un
set
de tous les arguments nomméss
et créer un dictionnaire qui mappe l'argument à lui-même entouré d'accolades:Utilisez maintenant le
args
dictionnaire pour renseigner les clés manquantesreplacements
. Pour python 3.5+, vous pouvez le faire dans une seule expression :Pour les anciennes versions de python, vous pouvez appeler
update
:la source
J'aime la réponse @ sven-marnach. Ma réponse en est simplement une version étendue. Il permet le formatage sans mot-clé et ignore les clés supplémentaires. Voici des exemples d'utilisation (le nom d'une fonction est une référence au formatage de chaîne f python 3.6):
Et voici mon code:
la source
Si vous faites beaucoup de modèles et que vous trouvez que la fonctionnalité de modèles de chaînes intégrée de Python est insuffisante ou maladroite, regardez Jinja2 .
À partir de la documentation:
la source
En lisant le commentaire de @Sam Bourne, j'ai modifié le code de @ SvenMarnach pour qu'il fonctionne correctement avec la coercition (comme
{a!s:>2s}
) sans écrire un analyseur personnalisé. L'idée de base n'est pas de convertir en chaînes mais de concaténer les clés manquantes avec des balises de coercition.Utilisez (par exemple) comme ceci
Les tests suivants (inspirés des tests de @ norok2) vérifient la sortie pour le traditionnel
format_map
et unsafe_format_map
basé sur la classe ci-dessus dans deux cas: fournir des mots-clés corrects ou sans eux.Quelles sorties
la source
Vous pouvez l'envelopper dans une fonction qui prend les arguments par défaut:
la source