Je voudrais utiliser Python chaîne format()
pour agir comme un modèle rapide et sale. Cependant, le dict
que je voudrais utiliser a des clés qui sont des (représentations de chaîne) d'entiers. un exemple simplifié suit:
s = 'hello there {5}'
d = {'5': 'you'}
s.format(**d)
le code ci-dessus renvoie l'erreur suivante:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: Tuple index out of range
est-il possible de faire ce qui précède?
Nous avons établi que cela ne fonctionnera pas, mais que diriez-vous d'une solution:
Bien que str.format
ne fonctionnera pas dans ce cas, assez drôle l'ancien %
formatage. Ce n'est pas recommandé, mais vous avez demandé un modèle rapide et sale.
>>> 'hello there %(5)s' % {'5': 'you'}
'hello there you'
Notez cependant que cela ne fonctionnera pas pour les clés entières.
>>> 'hello there %(5)s' % {5: 'you'}
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
'hello there %(5)s' % {5: 'you'}
KeyError: '5'
J'adore l'idée d'étendre le formateur afin qu'il autorise des noms de champs arbitraires (entiers, noms de champs avec deux points, etc.). Une implémentation pourrait ressembler à ceci:
import string, re
class QuFormatter(string.Formatter):
def _quote(self, m):
if not hasattr(self, 'quoted'):
self.quoted = {}
key = '__q__' + str(len(self.quoted))
self.quoted[key] = m.group(2)
return '{' + m.group(1) + key + m.group(3) + '}'
def parse(self, format_string):
return string.Formatter.parse(self,
re.sub(r'{([^}`]*)`([^}`]*)`([^}]*)}', self._quote, format_string))
def get_value(self, key, args, kwargs):
if key.startswith('__q__'):
key = self.quoted[key]
return string.Formatter.get_value(self, key, args, kwargs)
Usage:
d = {'5': 'you', '6': 'me', "okay":1, "weird:thing!": 123456}
print QuFormatter().format(
'hello there {`5`} {`6`:20s}--{okay}--{`weird:thing!`:20,d}',
**d)
Les champs en guillemets sont donc traités littéralement.
Voir cet article pour les réponses à vos problèmes. Il semble que vous ne puissiez pas utiliser des chaînes composées de nombres comme clés de dictionnaire dans les chaînes de format ( lien docs ).
Si vous pouvez utiliser une clé autre que 5, cela fonctionnera:
my_string='hello there {spam:s}'
d={'spam': 'you'}
print my_string.format(**d) # Returns "hello there you"
De PEP 3101
La classe de chaîne intégrée (et également la classe unicode en 2.6) gagnera une nouvelle méthode, 'format', qui prend un nombre arbitraire d'arguments positionnels et de mots clés:
"The story of {0}, {1}, and {c}".format(a, b, c=d)
Dans une chaîne de format, chaque argument positionnel est identifié par un nombre, à partir de zéro, donc dans l'exemple ci-dessus, 'a' est l'argument 0 et 'b' est l'argument 1. Chaque argument de mot-clé est identifié par son nom de mot-clé, donc dans l'exemple ci-dessus, "c" est utilisé pour faire référence au troisième argument.
Valeurs numériques utilisées dans str.format
sont des arguments positionnels. Vous ne pouvez donc pas faire cela.
Vous pouvez joindre le PEP 3101 depuis ici . La section connexe est sous Méthodes de chaîne
Comme @Volatility l'a mentionné, vous pouvez utiliser %
formateur pour cela.
Vous pouvez faire quelque chose avec get_value
Dans un string.Formatter
Personnalisé pour essayer les champs de remplacement comme clés de dictionnaire avant de retomber sur l'index en clés arg - notez le conflit possible de priorité et d'intention ici ... donc c'est pas exactement recommandé, mais une idée de ce qui est possible:
import string
class MyFormatter(string.Formatter):
def get_value(self, key, args, kwargs):
try:
return kwargs[str(key)]
except KeyError:
return super(MyFormatter, self).get_value(key, args, kwargs)
s = 'hello there {5} - you are number {0}'
d = {'5': 'you'}
print MyFormatter().format(s, 1, 2, 3, **d)
# hello there you - you are number 1
C'est effectivement possible, en utilisant le fait {k}
cherche le (k+1)
th argument positionnel.
def populate_list(d):
""" Return a list l verifying l[k] = d[str(k)] for each natural k """
return [d.get(str(k)) for k in range(1 + max(map(int, d)))] if d else []
def format_with_int_keys(s,d):
""" Replace each {k} in s by d[str(k)] """
return s.format(*populate_list(d))
s = 'hello there {5}'
d = {'5': 'you'}
print (format_with_int_keys(s,d))
Edit: Il s'agit en fait d'une version détaillée de la solution @wim.