Question Formatage de chaîne Python:% par rapport à .format


Python 2.6 a introduit le str.format() méthode avec une syntaxe légèrement différente de l'existant % opérateur. Quel est le meilleur et pour quelles situations?

  1. Ce qui suit utilise chaque méthode et a le même résultat, alors quelle est la différence?

    #!/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!"
    
  2. De plus, quand la mise en forme des chaînes se produit-elle en Python? Par exemple, si mon niveau de consignation est défini sur Élevé, j'obtiendrai un résultat pour effectuer les opérations suivantes: % opération? Et si oui, y a-t-il un moyen d'éviter cela?

    log.debug("some debug info: %s" % some_info)
    

1178
2018-02-22 18:46


origine


Réponses:


Pour répondre à votre première question ... .format semble simplement plus sophistiqué à bien des égards. Une chose agaçante à propos de % est aussi comment il peut soit prendre une variable ou un tuple. Vous penseriez que ce qui suit fonctionnerait toujours:

"hi there %s" % name

pourtant, si name s'avère être (1, 2, 3), il va jeter un TypeError. Pour garantir qu'il imprime toujours, vous devez faire

"hi there %s" % (name,)   # supply the single argument as a single-item tuple

ce qui est juste moche. .format n'a pas ces problèmes. Dans le deuxième exemple que vous avez donné, le .format exemple est beaucoup plus propre.

Pourquoi ne l'utiliseriez-vous pas?

  • ne pas savoir à ce sujet (moi avant de lire ceci)
  • avoir à être compatible avec Python 2.5

Pour répondre à votre deuxième question, la mise en forme de chaîne se produit en même temps que toute autre opération - lorsque l'expression de mise en forme de chaîne est évaluée. Et Python, n'étant pas un langage paresseux, évalue les expressions avant d'appeler des fonctions, donc dans votre log.debug exemple, l'expression "some debug info: %s"%some_infoévaluera d'abord, par ex. "some debug info: roflcopters are active", alors cette chaîne sera passée à log.debug().


852
2018-02-22 18:49



Quelque chose que l'opérateur modulo (%) ne peut pas faire, afaik:

tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)

résultat

12 22222 45 22222 103 22222 6 22222

Très utile.

Un autre point: format(), étant une fonction, peut être utilisé comme argument dans d'autres fonctions:

li = [12,45,78,784,2,69,1254,4785,984]
print map('the number is {}'.format,li)   

print

from datetime import datetime,timedelta

once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
delta = timedelta(days=13, hours=8,  minutes=20)

gen =(once_upon_a_time +x*delta for x in xrange(20))

print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))

Résulte en:

['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']

2010-07-01 12:00:00
2010-07-14 20:20:00
2010-07-28 04:40:00
2010-08-10 13:00:00
2010-08-23 21:20:00
2010-09-06 05:40:00
2010-09-19 14:00:00
2010-10-02 22:20:00
2010-10-16 06:40:00
2010-10-29 15:00:00
2010-11-11 23:20:00
2010-11-25 07:40:00
2010-12-08 16:00:00
2010-12-22 00:20:00
2011-01-04 08:40:00
2011-01-17 17:00:00
2011-01-31 01:20:00
2011-02-13 09:40:00
2011-02-26 18:00:00
2011-03-12 02:20:00

281
2018-06-13 20:20



En supposant que vous utilisez Python logging module, vous pouvez passer les arguments de formatage de chaîne comme arguments au .debug() méthode plutôt que de faire le formatage vous-même:

log.debug("some debug info: %s", some_info)

ce qui évite de faire le formatage à moins que l'enregistreur n'enregistre quelque chose.


124
2018-02-22 19:21



À partir de Python 3.6 (2016), vous pouvez utiliser f-cordes pour substituer des variables:

>>> origin = "London"
>>> destination = "Paris"
>>> f"from {origin} to {destination}"
'from London to Paris'

Noter la f" préfixe. Si vous essayez ceci dans Python 3.5 ou plus tôt, vous obtiendrez un SyntaxError.

Voir https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings


88
2018-04-15 11:12



PEP 3101 propose le remplacement du % l'opérateur avec la nouvelle mise en forme de chaîne avancée dans Python 3, où il serait la valeur par défaut.


54
2017-08-01 03:01



Mais s'il vous plaît soyez prudent, tout à l'heure j'ai découvert un problème en essayant de remplacer tous % avec .format dans le code existant: '{}'.format(unicode_string) va essayer d'encoder unicode_string et échouera probablement.

Regardez ce journal de session interactive Python:

Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'

s est juste une chaîne (appelée 'byte array' dans Python3) et u est une chaîne Unicode (appelée 'chaîne' dans Python3):

; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'

Lorsque vous donnez un objet Unicode en tant que paramètre à % il va produire une chaîne Unicode même si la chaîne d'origine n'était pas Unicode:

; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)

mais le .format La fonction va lever "UnicodeEncodeError":

; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'

et cela fonctionnera avec un argument Unicode uniquement si la chaîne d'origine était Unicode.

; '{}'.format(u'i')
'i'

ou si la chaîne d'argument peut être convertie en chaîne (appelée 'byte array')


51
2017-09-03 18:15



Encore un autre avantage de .format (que je ne vois pas dans les réponses): il peut prendre des propriétés d'objet.

In [12]: class A(object):
   ....:     def __init__(self, x, y):
   ....:         self.x = x
   ....:         self.y = y
   ....:         

In [13]: a = A(2,3)

In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'

Ou, en tant qu'argument mot-clé:

In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'

Ce n'est pas possible avec % autant que je peux dire.


33
2017-12-04 18:33



Comme je l'ai découvert aujourd'hui, l'ancienne façon de formater les chaînes via % ne supporte pas Decimal, Le module de Python pour le point fixe décimal et l'arithmétique à virgule flottante, prêt à l'emploi.

Exemple (en utilisant Python 3.3.5):

#!/usr/bin/env python3

from decimal import *

getcontext().prec = 50
d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard

print('%.50f' % d)
print('{0:.50f}'.format(d))

Sortie:

0,00000000000000000000000312375239000000009907464850   0,00000000000000000000000312375239000000000000000000

Il pourrait sûrement y avoir des solutions de rechange, mais vous pourriez toujours envisager d'utiliser le format() méthode tout de suite.


27
2018-05-13 17:10



% donne de meilleures performances que format de mon test.

Code de test:

Python 2.7.2:

import timeit
print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")

Résultat:

> format: 0.470329046249
> %: 0.357107877731

Python 3.5.2

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))

Résultat

> format: 0.5864730989560485
> %: 0.013593495357781649

Il regarde dans Python2, la différence est faible alors que dans Python3, % est beaucoup plus rapide que format.

Merci @Chris Cogdon pour l'exemple de code.


20
2018-06-13 18:43



En remarque, vous n'avez pas besoin d'effectuer un hit de performance pour utiliser le nouveau formatage de style avec la journalisation. Vous pouvez passer n'importe quel objet à logging.debug, logging.info, etc. qui met en œuvre __str__ méthode magique. Lorsque le module de journalisation a décidé qu'il doit émettre votre objet de message (quel qu'il soit), il appelle str(message_object) avant de le faire. Donc, vous pouvez faire quelque chose comme ça:

import logging


class NewStyleLogMessage(object):
    def __init__(self, message, *args, **kwargs):
        self.message = message
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        args = (i() if callable(i) else i for i in self.args)
        kwargs = dict((k, v() if callable(v) else v) for k, v in self.kwargs.items())

        return self.message.format(*args, **kwargs)

N = NewStyleLogMessage

# Neither one of these messages are formatted (or calculated) until they're
# needed

# Emits "Lazily formatted log entry: 123 foo" in log
logging.debug(N('Lazily formatted log entry: {0} {keyword}', 123, keyword='foo'))


def expensive_func():
    # Do something that takes a long time...
    return 'foo'

# Emits "Expensive log entry: foo" in log
logging.debug(N('Expensive log entry: {keyword}', keyword=expensive_func))

Tout ceci est décrit dans la documentation de Python 3 (https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles). Cependant, cela fonctionnera aussi avec Python 2.6 (https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages).

Un des avantages de l'utilisation de cette technique, outre le fait qu'elle est agnostique de style de formatage, est qu'elle permet des valeurs paresseuses, par ex. la fonction expensive_func au dessus. Ceci fournit une alternative plus élégante au conseil donné dans les docs de Python ici: https://docs.python.org/2.6/library/logging.html#optimization.


14
2017-08-21 18:00



Une situation où % peut vous aider lorsque vous formatez des expressions regex. Par exemple,

'{type_names} [a-z]{2}'.format(type_names='triangle|square')

soulève IndexError. Dans cette situation, vous pouvez utiliser:

'%(type_names)s [a-z]{2}' % {'type_names': 'triangle|square'}

Cela évite d'écrire l'expression régulière comme '{type_names} [a-z]{{2}}'. Cela peut être utile lorsque vous avez deux regex, où l'un est utilisé seul sans format, mais la concaténation des deux est formatée.


8
2018-04-09 20:41