web-dev-qa-db-fra.com

Format des chaînes vs concaténation

Je vois beaucoup de gens utiliser des chaînes de format comme ceci:

root = "sample"
output = "output"
path = "{}/{}".format(root, output)

Au lieu de simplement concaténer des chaînes comme celle-ci:

path = root + '/' + output

Les chaînes de format ont-elles de meilleures performances ou est-ce juste pour l'apparence?

30
wjk2a1

C'est juste pour les looks. Vous pouvez voir en un coup d'œil quel est le format. Beaucoup d'entre nous préfèrent la lisibilité à la micro-optimisation.

Voyons ce que l'IPython %timeit dit:

Python 3.7.2 (default, Jan  3 2019, 02:55:40)
IPython 5.8.0
Intel(R) Core(TM) i5-4590T CPU @ 2.00GHz

In [1]: %timeit root = "sample"; output = "output"; path = "{}/{}".format(root, output)
The slowest run took 12.44 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 5: 223 ns per loop

In [2]: %timeit root = "sample"; output = "output"; path = root + '/' + output
The slowest run took 13.82 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 5: 101 ns per loop

In [3]: %timeit root = "sample"; output = "output"; path = "%s/%s" % (root, output)
The slowest run took 27.97 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 5: 155 ns per loop

In [4]: %timeit root = "sample"; output = "output"; path = f"{root}/{output}"
The slowest run took 19.52 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 5: 77.8 ns per loop
25
kay

Comme avec la plupart des choses, il y aura une différence de performances, mais demandez-vous "Est-ce vraiment important si c'est plus rapide ns?". Le root + '/' output la méthode est rapide et facile à taper. Mais cela peut être difficile à lire très rapidement lorsque vous avez plusieurs variables à imprimer

foo = "X = " + myX + " | Y = " + someY + " Z = " + Z.toString()

contre

foo = "X = {} | Y= {} | Z = {}".format(myX, someY, Z.toString())

Qu'est-ce qui est plus facile à comprendre ce qui se passe? À moins que vous vraiment ayez besoin de fuir les performances, choisissez la façon la plus facile à lire et à comprendre pour les gens

11
FuriousGeorge

Ce n'est pas seulement pour des "looks", ou pour de puissantes conversions de type lexical; c'est aussi un incontournable de l'internationalisation.

Vous pouvez échanger la chaîne de format en fonction de la langue sélectionnée.

Avec une longue ligne de concaténations de chaînes intégrées dans le code source, cela devient effectivement impossible à faire correctement.

10

Le format de chaîne est exempt de type de données lors de la liaison de données. Pendant la concaténation, nous devons taper cast ou convertir les données en conséquence.

Par exemple:

a = 10
b = "foo"
c = str(a) + " " + b
print c
> 10 foo

Cela pourrait être fait via un formatage de chaîne comme:

a = 10
b = "foo"
c = "{} {}".format(a, b)
print c
> 10 foo

Tels que les espaces réservés {} {}, nous supposons que deux choses vont plus loin, à savoir, dans ce cas, sont a et b.

9
Half Genius

Je suis d'accord que le formatage est principalement utilisé pour la lisibilité, mais depuis la sortie des f-strings en 3.6, les tableaux ont changé en termes de performances. Je pense également que les chaînes f sont plus lisibles/maintenables car 1) elles peuvent être lues de gauche à droite comme la plupart des textes normaux et 2) les inconvénients liés à l'espacement de la concaténation sont évités car les variables sont en chaîne.

Exécution de ce code:

from timeit import timeit

runs = 1000000


def print_results(time, start_string):
    print(f'{start_string}\n'
          f'Total: {time:.4f}s\n'
          f'Avg: {(time/runs)*1000000000:.4f}ns\n')


t1 = timeit('"%s, %s" % (greeting, loc)',
            setup='greeting="hello";loc="world"',
            number=runs)
t2 = timeit('f"{greeting}, {loc}"',
            setup='greeting="hello";loc="world"',
            number=runs)
t3 = timeit('greeting + ", " + loc',
            setup='greeting="hello";loc="world"',
            number=runs)
t4 = timeit('"{}, {}".format(greeting, loc)',
            setup='greeting="hello";loc="world"',
            number=runs)

print_results(t1, '% replacement')
print_results(t2, 'f strings')
print_results(t3, 'concatenation')
print_results(t4, '.format method')

donne ce résultat sur ma machine:

% replacement
Total: 0.3044s
Avg: 304.3638ns

f strings
Total: 0.0991s
Avg: 99.0777ns

concatenation
Total: 0.1252s
Avg: 125.2442ns

.format method
Total: 0.3483s
Avg: 348.2690ns

Une réponse similaire à une question différente est donnée le cette réponse .

9
Eric Ed Lohmar

À partir de Python 3.6 vous pouvez faire interpolation littérale de chaîne en précédant f de la chaîne:

root = "sample"
output = "output"
path = f"{root}/{output}"
6
Cyzanfar

C'est pour l'apparence et le maintien du code. Il est vraiment plus facile de modifier votre code si vous avez utilisé le format. De plus, lorsque vous utilisez +, vous risquez de manquer les détails tels que les espaces. Utilisez le format pour votre bien et celui des mainteneurs possibles.

2
Doruk