Formatage des chaînes:% contre .format

1350

Python 2.6 a introduit la str.format()méthode avec une syntaxe légèrement différente de celle de l' %opérateur existant . Quelle est la meilleure 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 le formatage des chaînes se produit-il en Python? Par exemple, si mon niveau de journalisation est défini sur ÉLEVÉ, vais-je quand même prendre un coup pour effectuer l' %opération suivante ? Et si oui, existe-t-il un moyen d'éviter cela?

    log.debug("some debug info: %s" % some_info)
NorthIsUp
la source
2
Pour les débutants: voici un très joli tutoriel qui enseigne les deux styles. Personnellement, j'utilise le %style plus ancien plus souvent, car si vous n'avez pas besoin des capacités améliorées du format()style, le %style est souvent beaucoup plus pratique.
Lutz Prechelt
2
Pour référence: documentation Python 3 pour le plus récent de format()style mise en forme et plus à %base de style de formatage .
Lutz Prechelt
1
Pour répondre à votre deuxième question, depuis la version 3.2, vous pouvez utiliser le format {} si vous utilisez un formateur personnalisé (voir docs.python.org/3/library/logging.html#logging.Formatter )
yanjost

Réponses:

953

Pour répondre à votre première question ... .formatsemble juste plus sophistiqué à bien des égards. Une chose ennuyeuse %est également de savoir comment il peut prendre une variable ou un tuple. On pourrait penser que ce qui suit fonctionnerait toujours:

"hi there %s" % name

pourtant, si namecela arrive (1, 2, 3), il lancera 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 tout simplement moche. .formatn'a pas ces problèmes. Toujours dans le deuxième exemple que vous avez donné, l' .formatexemple est beaucoup plus propre.

Pourquoi ne l'utiliseriez-vous pas?

  • ne pas le savoir (moi avant de lire ceci)
  • être compatible avec Python 2.5

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

Claudiu
la source
113
"%(a)s, %(a)s" % {'a':'test'}
ted
128
Notez que vous perdrez du temps pour log.debug("something: %s" % x)mais pas pour log.debug("something: %s", x) La mise en forme des chaînes sera gérée dans la méthode et vous n'obtiendrez pas les performances si elle n'est pas enregistrée. Comme toujours, Python anticipe vos besoins =)
darkfeline
63
ted: c'est un hack plus mauvais pour faire la même chose que '{0}, {0}'.format('test').
vol de moutons
19
Le point est le suivant: le seul argument récurrent selon lequel la nouvelle syntaxe permet la réorganisation des éléments est un point discutable: vous pouvez faire de même avec l'ancienne syntaxe. La plupart des gens ne savent pas que cela est déjà défini dans l'Ansi C99 Std! Consultez une copie récente de man sprintfet découvrez la $notation à l'intérieur des %espaces réservés
cfi
29
@cfi: Si vous voulez dire quelque chose comme, printf("%2$d", 1, 3)pour imprimer "3", c'est spécifié dans POSIX, pas C99. La page de manuel que vous avez référencée note: «La norme C99 n'inclut pas le style utilisant« $ »…»
Thanatos
307

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
eyquem
la source
17
Vous pouvez utiliser la mise en forme à l'ancienne mapaussi facilement que le format. map('some_format_string_%s'.__mod__, some_iterable)
2012
3
@cfi: veuillez prouver que vous avez raison en réécrivant l'exemple ci-dessus dans C99
MarcH
9
@MarcH: printf("%2$s %1$s\n", "One", "Two");compilé avec gcc -std=c99 test.c -o test, la sortie est Two One. Mais je suis corrigé: c'est en fait une extension POSIX et non C. Je ne peux pas la retrouver dans le standard C / C ++, où je pensais l'avoir vue. Le code fonctionne même avec le drapeau std «c90». sprintfpage de manuel . Cela ne le répertorie pas, mais permet aux bibliothèques d'implémenter un sur-ensemble. Mon argument d'origine est toujours valable, en le remplaçant CparPosix
cfi
8
Mon premier commentaire ici, ne s'applique pas à cette réponse. Je regrette la formulation. En Python, nous ne pouvons pas utiliser l'opérateur modulo %pour réorganiser les espaces réservés. Je voudrais toujours ne pas supprimer ce premier commentaire par souci de cohérence des commentaires ici. Je m'excuse d'avoir évacué ma colère ici. Elle est dirigée contre l'affirmation souvent faite que l'ancienne syntaxe en soi ne le permettrait pas. Au lieu de créer une syntaxe complètement nouvelle, nous aurions pu introduire les extensions std Posix. Nous pourrions avoir les deux.
cfi
17
'modulo' fait référence à l'opérateur qui évalue un reste après une division. dans ce cas, le signe pourcentage n'est pas un opérateur modulo.
Octopus
148

En supposant que vous utilisez le loggingmodule de Python , vous pouvez passer les arguments de formatage de chaîne comme arguments à la .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 réellement quelque chose.

Wooble
la source
10
Voici quelques informations utiles que je viens d'apprendre. Dommage qu'il n'ait pas sa propre question car il semble séparé de la question principale. Dommage que le PO n'ait pas divisé sa question en deux questions distinctes.
snth
12
Vous pouvez utiliser le formatage dict comme ceci: log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry')) Cependant, vous ne pouvez pas utiliser la nouvelle .format()syntaxe de style ici, pas même en Python 3.3, ce qui est dommage.
Cito
15
@Cito: Voir ceci: plumberjack.blogspot.co.uk/2010/10/…
Vinay Sajip
26
Le principal avantage de ceci n'est pas la performance (faire l'interpolation de chaîne sera rapide par rapport à tout ce que vous faites avec la sortie de la journalisation, par exemple l'affichage dans un terminal, l'enregistrement sur le disque). C'est que si vous avez un agrégateur de journalisation, il peut vous dire "vous avez obtenu 12 instances de ce message d'erreur", même si elles avaient toutes des valeurs "some_info" différentes. Si le formatage de la chaîne est effectué avant de transmettre la chaîne à log.debug, cela est impossible. L'agrégateur ne peut dire que "vous aviez 12 messages de journal différents"
Jonathan Hartley
7
Si les performances vous inquiètent, utilisez la syntaxe dict {} littérale au lieu d'une instanciation de classe dict (): doughellmann.com/2012/11/…
trojjer
119

Depuis Python 3.6 (2016), vous pouvez utiliser des chaînes f pour remplacer des variables:

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

Notez le f"préfixe. Si vous essayez ceci dans Python 3.5 ou une version antérieure, vous obtiendrez un SyntaxError.

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

Colonel Panic
la source
1
Cela ne répond pas à la question. Une autre réponse qui mentionne les chaînes f parle au moins de performances: stackoverflow.com/a/51167833/7851470
Georgy
60

PEP 3101 propose de remplacer l' %opérateur par le nouveau formatage de chaîne avancé en Python 3, où ce serait la valeur par défaut.

Idée de génie
la source
14
Faux: "La compatibilité descendante peut être maintenue en laissant les mécanismes existants en place."; bien sûr, .formatne remplacera pas le %formatage des chaînes.
Tobias
12
Non, la postulation de BrainStorms est vraie: "destinée à remplacer le '%' existant". La citation de Tobias signifie que les deux systèmes coexisteront pendant un certain temps. RTFPEP
phobie
54

Mais soyez prudent, je viens de découvrir un problème en essayant de tout remplacer %par .formatdu code existant: '{}'.format(unicode_string)va essayer d'encoder unicode_string et échouera probablement.

Regardez simplement ce journal de session interactif 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'

sest juste une chaîne (appelée «tableau d'octets» en Python3) et uest une chaîne Unicode (appelée «chaîne» en Python3):

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

Lorsque vous donnez un objet Unicode comme paramètre à l' %opérateur, il produira 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 la .formatfonction lèvera "UnicodeEncodeError":

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

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

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

ou si la chaîne d'argument peut être convertie en une chaîne (appelée "tableau d'octets")

wobmene
la source
12
Il n'y a tout simplement aucune raison de changer le code de travail à moins que les fonctionnalités supplémentaires de la nouvelle formatméthode ne soient vraiment nécessaires ...
Tobias
Je suis absolument d'accord avec toi, Tobias, mais parfois cela est nécessaire lors de la mise à niveau vers de nouvelles versions de Python
wobmene
2
Par exemple? AFAIK, cela n'a jamais été nécessaire; Je ne pense pas qu'il soit probable que l' %interpolation de chaîne disparaisse.
Tobias
4
Je considère la fonction .format () plus sûre que% pour les chaînes. Souvent, je vois des erreurs de débutants comme ça "p1=%s p2=%d" % "abc", 2ou "p1=%s p2=%s" % (tuple_p1_p2,). Vous pourriez penser que c'est la faute du codeur, mais je pense que c'est juste une syntaxe défectueuse bizarre qui semble agréable pour le quicky-scriptie mais qui est mauvaise pour le code de production.
wobmene
3
Mais je n'aime pas la syntaxe de .format (), je serais plus heureux avec du bon vieux %s, %02dcomme "p1=%s p2=%02d".format("abc", 2). Je blâme ceux qui ont inventé et approuvé le formatage des accolades bouclés qui a besoin de vous pour leur échapper {{}}et qui a l'air moche.
wobmene
35

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, comme argument de 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 %pour autant que je sache.

matiasg
la source
4
Cela semble plus illisible que nécessaire par rapport à l'équivalent 'x is {0}, y is {1}'.format(a.x, a.y). Ne doit être utilisé que lorsque l' a.xopération est très coûteuse.
dtheodor
13
@dtheodor Avec un tweak d'utiliser un argument mot - clé au lieu d'argument de position ... 'x is {a.x}, y is {a.y}'.format(a=a). Plus lisible que les deux exemples.
CivFan
1
@CivFan Ou, si vous avez plus d'un objet,'x is {a.x}, y is {a.y}'.format(**vars())
Jack
1
A noter également celui de la même façon: '{foo[bar]}'.format(foo={'bar': 'baz'}).
Antoine Pinsard
3
Cela est extrêmement utile pour les applications destinées aux clients, où votre application fournit un ensemble standard d'options de formatage avec une chaîne de format fournie par l'utilisateur. Je l'utilise tout le temps. Le fichier de configuration, par exemple, aura une propriété "messagestring", que l'utilisateur peut fournir Your order, number {order[number]} was processed at {now:%Y-%m-%d %H:%M:%S}, will be ready at about {order[eta]:%H:%M:%S}ou ce qu'il veut. C'est beaucoup plus propre que d'essayer d'offrir les mêmes fonctionnalités avec l'ancien formateur. Il rend les chaînes de format fournies par l'utilisateur beaucoup plus puissantes.
Taywee
35

%donne de meilleures performances que formatde 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 en Python2, la différence est petite alors qu'en Python3, %est beaucoup plus rapide que format.

Merci @Chris Cogdon pour l'exemple de code.

Modifier 1:

Testé à nouveau dans Python 3.7.2 en juillet 2019.

Résultat:

> format: 0.86600608
> %: 0.630180146

Il n'y a pas beaucoup de différence. Je suppose que Python s'améliore progressivement.

Modifier 2:

Après que quelqu'un ait mentionné la f-string de python 3 en commentaire, j'ai fait un test pour le code suivant sous python 3.7.2:

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

Résultat:

format: 0.8331376779999999
%: 0.6314778750000001
f-string: 0.766649943

Il semble que la f-string soit encore plus lente %mais meilleure que format.

lcltj
la source
42
Au lieu de cela, str.formatdonne plus de fonctionnalités (en particulier le formatage spécialisé par exemple '{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())). La performance ne peut pas être l'exigence absolue de tous les emplois. Utilisez le bon outil pour le travail.
minhee
36
"L'optimisation prématurée est la racine de tout mal", disait Donald Knuth ...
Yatharth Agarwal
22
S'en tenir à un schéma de formatage bien connu (tant qu'il convient aux besoins, ce qu'il fait dans la grande majorité des cas), et qui est deux fois plus rapide, n'est pas une "optimisation prématurée" mais simplement raisonnable. BTW, l' %opérateur permet de réutiliser les printfconnaissances; L'interpolation de dictionnaire est une extension très simple du principe.
Tobias
5
J'ai en fait vécu le contraire dans une situation. La mise en forme d'un nouveau style était plus rapide. Pouvez-vous fournir le code de test que vous avez utilisé?
David Sanders
8
On dirait un message sérieusement gaspillé sans aucun exemple ou raisonnement, juste des réclamations.
kevr
31

Comme je l'ai découvert aujourd'hui, l'ancienne méthode de formatage des chaînes via %ne prend pas en charge Decimalle module Python pour l'arithmétique décimale à virgule fixe et à 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))

Production:

0.00000000000000000000000312375239000000009907464850 0.000000000000000000000003123752390000000000000000000000

Il peut certainement y avoir des solutions, mais vous pouvez toujours envisager d'utiliser la format()méthode tout de suite.

balu
la source
1
C'est probablement parce que la mise en forme de nouveau style appelle str(d)avant d'étendre le paramètre, tandis que la mise en forme de style ancien appelle probablement en float(d)premier.
David Sanders
3
On pourrait le penser, mais str(d)revient "3.12375239e-24", pas"0.00000000000000000000000312375239000000000000000000"
Jack
18

Si votre python> = 3,6, le littéral au format F-string est votre nouvel ami.

C'est une performance plus simple, propre et meilleure.

In [1]: params=['Hello', 'adam', 42]

In [2]: %timeit "%s %s, the answer to everything is %d."%(params[0],params[1],params[2])
448 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [3]: %timeit "{} {}, the answer to everything is {}.".format(*params)
449 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit f"{params[0]} {params[1]}, the answer to everything is {params[2]}."
12.7 ns ± 0.0129 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
zhengcao
la source
15

En guise de remarque, vous n'avez pas besoin de prendre un coup de performance pour utiliser la nouvelle mise en forme de style avec la journalisation. Vous pouvez passer à tout objet logging.debug, logging.infoetc. , qui met en œuvre la __str__méthode magique. Lorsque le module de journalisation a décidé qu'il doit émettre votre objet message (quel qu'il soit), il appelle str(message_object)avant de le faire. Vous pouvez donc faire quelque chose comme ceci:

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 cela est décrit dans la documentation Python 3 ( https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). Cependant, cela fonctionnera également 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 indépendante du formatage, est qu'elle permet des valeurs paresseuses, par exemple la fonction expensive_funcci-dessus. Cela fournit une alternative plus élégante aux conseils donnés dans les documents Python ici: https://docs.python.org/2.6/library/logging.html#optimization .

David Sanders
la source
2
J'aimerais pouvoir voter davantage. Il permet de se connecter formatsans affecter les performances - le fait en remplaçant __str__précisément comme loggingprévu - raccourcit l'appel de fonction à une seule lettre ( N) qui ressemble beaucoup à certaines des méthodes standard pour définir des chaînes - ET permet de paresseux appel de fonction. Je vous remercie! +1
CivFan
2
Le résultat est-il différent de l'utilisation du logging.Formatter(style='{')paramètre?
davidA
10

Une situation où %peut aider est 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 sous la forme '{type_names} [a-z]{{2}}'. Cela peut être utile lorsque vous avez deux expressions rationnelles, où l'une est utilisée seule sans format, mais la concaténation des deux est formatée.

Jorge Leitao
la source
3
Ou utilisez simplement '{type_names} [a-z]{{2}}'.format(type_names='triangle|square'). C'est comme dire que cela .format()peut aider lors de l'utilisation de chaînes qui contiennent déjà un pourcentage. Sûr. Vous devez alors leur échapper.
Alfe
1
@Alfe Vous avez raison, et c'est pourquoi la réponse commence par "One situation where % may help is when you are formatting regex expressions."Plus précisément, supposez qu'il a=r"[a-z]{2}"s'agit d'un bloc d'expression régulière que vous utiliserez dans deux expressions finales différentes (par exemple c1 = b + aet c2 = a). Supposons que cela c1doit être formatédité (par exemple bdoit être formaté au moment de l'exécution), mais c2pas. Ensuite, vous avez besoin a=r"[a-z]{2}"de c2et a=r"[a-z]{{2}}"pour c1.format(...).
Jorge Leitao
7

J'ajouterais que depuis la version 3.6, nous pouvons utiliser des chaînes comme celles-ci

foo = "john"
bar = "smith"
print(f"My name is {foo} {bar}")

Qui donnent

Je m'appelle John Smith

Tout est converti en chaînes

mylist = ["foo", "bar"]
print(f"mylist = {mylist}")

Résultat:

mylist = ['foo', 'bar']

vous pouvez passer la fonction, comme dans la méthode des autres formats

print(f'Hello, here is the date : {time.strftime("%d/%m/%Y")}')

Donner par exemple

Bonjour, voici la date: 16/04/2018

Sylvan LE DEUNFF
la source
4

Pour la version python> = 3.6 (voir PEP 498 )

s1='albha'
s2='beta'

f'{s1}{s2:>10}'

#output
'albha      beta'
Roushan
la source
2

Comparatif Python 3.6.7:

#!/usr/bin/env python
import timeit

def time_it(fn):
    """
    Measure time of execution of a function
    """
    def wrapper(*args, **kwargs):
        t0 = timeit.default_timer()
        fn(*args, **kwargs)
        t1 = timeit.default_timer()
        print("{0:.10f} seconds".format(t1 - t0))
    return wrapper


@time_it
def new_new_format(s):
    print("new_new_format:", f"{s[0]} {s[1]} {s[2]} {s[3]} {s[4]}")


@time_it
def new_format(s):
    print("new_format:", "{0} {1} {2} {3} {4}".format(*s))


@time_it
def old_format(s):
    print("old_format:", "%s %s %s %s %s" % s)


def main():
    samples = (("uno", "dos", "tres", "cuatro", "cinco"), (1,2,3,4,5), (1.1, 2.1, 3.1, 4.1, 5.1), ("uno", 2, 3.14, "cuatro", 5.5),) 
    for s in samples:
        new_new_format(s)
        new_format(s)
        old_format(s)
        print("-----")


if __name__ == '__main__':
    main()

Production:

new_new_format: uno dos tres cuatro cinco
0.0000170280 seconds
new_format: uno dos tres cuatro cinco
0.0000046750 seconds
old_format: uno dos tres cuatro cinco
0.0000034820 seconds
-----
new_new_format: 1 2 3 4 5
0.0000043980 seconds
new_format: 1 2 3 4 5
0.0000062590 seconds
old_format: 1 2 3 4 5
0.0000041730 seconds
-----
new_new_format: 1.1 2.1 3.1 4.1 5.1
0.0000092650 seconds
new_format: 1.1 2.1 3.1 4.1 5.1
0.0000055340 seconds
old_format: 1.1 2.1 3.1 4.1 5.1
0.0000052130 seconds
-----
new_new_format: uno 2 3.14 cuatro 5.5
0.0000053380 seconds
new_format: uno 2 3.14 cuatro 5.5
0.0000047570 seconds
old_format: uno 2 3.14 cuatro 5.5
0.0000045320 seconds
-----
Felix Martinez
la source
3
Vous devez exécuter chaque exemple plusieurs fois, une seule exécution peut être trompeuse, par exemple le système d'exploitation peut être généralement occupé, donc l'exécution de votre code est retardée. voir la documentation: docs.python.org/3/library/timeit.html . (gentil avatar, Guybrush!)
jake77
1

Mais une chose est que si vous avez des accolades imbriquées, cela ne fonctionnera pas pour le format mais %fonctionnera.

Exemple:

>>> '{{0}, {1}}'.format(1,2)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    '{{0}, {1}}'.format(1,2)
ValueError: Single '}' encountered in format string
>>> '{%s, %s}'%(1,2)
'{1, 2}'
>>> 
U10-Forward
la source
2
vous pouvez le faire, mais je suis d'accord, c'est génial '{{{0}, {1}}}'. format (1, 2)
Sylvan LE DEUNFF
Les accolades de mots clés imbriqués fonctionnent et sont jolies.
CivFan