Il existe actuellement trois types de fonctionnalités en Python qui sont équivalentes au sprintf de C. (La chaîne F
est exclue car elle n'utilise pas de chaîne de format)
Nom? | Comment utiliser |
---|---|
% -formatting |
fmt % values |
str.format() |
fmt.format(*values) / fmt.format(**values) |
Template strings | string.Template(fmt).substitute(**values) |
Cet article résume comment savoir combien d'éléments de tapple sont nécessaires dans la partie values
du tableau ci-dessus, ou les clés du dictionnaire.
Pour être honnête, je pense que c'est une connaissance assez rarement utilisée, mais cela peut être utile lorsque vous créez votre propre Formatter en héritant de logging.Formatter
.
--%
-formatting → Echec du formatage et voir l'exception.
str.format
→ string.Formatter().parser(fmt)
string.Template.pattern.finditer(fmt)
%
-formatting (printf style formatting)
Contrairement aux deux autres, je ne trouve pas de fonction dédiée pour l'analyse dans le package standard, donc je ferai de mon mieux.
Cette fois, j'ai créé une fonction pour déchiffrer en fonction de l'exception renvoyée. Si le type demandé dans la partie values
de fmt% values
est un taple, sa longueur est retournée, et s'il s'agit d'un dictionnaire, sa clé est retournée.
def parse_printf_style_format(fmt):
if not isinstance(fmt, (bytes, str)):
raise TypeError('got ' + type(fmt).__name__)
try:
fmt % ()
except TypeError as e:
if e.args[0] == 'not enough arguments for format string':
values = ()
elif e.args[0] == 'format requires a mapping':
values = {}
else:
raise
else:
return None
if isinstance(values, tuple):
while True:
try:
fmt % values
except TypeError as e:
if e.args[0] == 'not enough arguments for format string':
values += (0,)
else:
raise ValueError('invalid format: ' + repr(fmt))
else:
return len(values)
elif isinstance(values, dict):
while True:
try:
fmt % values
except TypeError as e:
if e.args[0] == 'not enough arguments for format string':
raise ValueError('invalid format: ' + repr(fmt))
else:
raise
except KeyError as e:
values[e.args[0]] = 0
else:
return tuple(values.keys())
else:
assert False
Exemple d'utilisation
>>> parse_printf_style_format('%d %s %x')
3
>>> parse_printf_style_format('%(foo)s, %(bar)d')
('foo', 'bar')
str.format()
C'est un coup dur avec string.Formatter (). Parse (fmt)
. Pour plus de détails, reportez-vous au Document officiel.
>>> import string
>>> fmt = '{foo:s}, {{bar:d}}, and {:f}'
>>> list(string.Formatter().parse(fmt))
[('', 'foo', 's', None),
(', {', None, None, None),
('bar:d}', None, None, None),
(', and ', '', 'f', None)]
Template strings
C'est un coup dur avec string.Template.pattern.finditer (fmt)
.
L'expression régulière qui correspond à l'espace réservé est stockée dans l'attribut pattern
.
>>> import string
>>> fmt = '${this_is_braced} $$this_is_escaped $@this_is_invalid $this_is_named'
>>> print(string.Template.pattern.pattern)
\$(?:
(?P<escaped>\$) | # Escape sequence of two delimiters
(?P<named>[_a-z][_a-z0-9]*) | # delimiter and a Python identifier
{(?P<braced>[_a-z][_a-z0-9]*)} | # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
>>> [match.groupdict() for match in string.Template.pattern.finditer(fmt)]
[{'braced': 'this_is_braced', 'escaped': None, 'invalid': None, 'named': None},
{'braced': None, 'escaped': '$', 'invalid': None, 'named': None},
{'braced': None, 'escaped': None, 'invalid': '', 'named': None},
{'braced': None, 'escaped': None, 'invalid': None, 'named': 'this_is_named'}]
Le traitement à froid du formatage «%» est terrible.
Recommended Posts