it-swarm.com.de

String-Verkettung vs. String-Ersetzung in Python

In Python kann ich nicht sagen, wo und wann die Zeichenfolgenverkettung im Vergleich zur Zeichenfolgensubstitution verwendet wird. Ist die Verkettung von Zeichenfolgen eine eher stilistische als eine praktische Entscheidung, da die Leistung stark zugenommen hat?

Als konkretes Beispiel, wie sollte man mit der Konstruktion flexibler URIs umgehen:

DOMAIN = 'http://stackoverflow.com'
QUESTIONS = '/questions'

def so_question_uri_sub(q_num):
    return "%s%s/%d" % (DOMAIN, QUESTIONS, q_num)

def so_question_uri_cat(q_num):
    return DOMAIN + QUESTIONS + '/' + str(q_num)

Bearbeiten: Es wurden auch Vorschläge zum Hinzufügen einer Liste von Zeichenfolgen und zur Verwendung der benannten Ersetzung gemacht. Hierbei handelt es sich um Varianten des zentralen Themas: Welcher Weg ist der richtige Weg, dies zu welchem ​​Zeitpunkt zu tun? Danke für die Antworten!

98
gotgenes

Die Verkettung ist meiner Maschine entsprechend (deutlich) schneller. Aber stilistisch bin ich bereit, den Preis für die Substitution zu zahlen, wenn die Leistung nicht kritisch ist. Nun, und wenn ich eine Formatierung benötige, muss ich nicht einmal die Frage stellen ... es gibt keine andere Möglichkeit, als Interpolation/Templating zu verwenden.

>>> import timeit
>>> def so_q_sub(n):
...  return "%s%s/%d" % (DOMAIN, QUESTIONS, n)
...
>>> so_q_sub(1000)
'http://stackoverflow.com/questions/1000'
>>> def so_q_cat(n):
...  return DOMAIN + QUESTIONS + '/' + str(n)
...
>>> so_q_cat(1000)
'http://stackoverflow.com/questions/1000'
>>> t1 = timeit.Timer('so_q_sub(1000)','from __main__ import so_q_sub')
>>> t2 = timeit.Timer('so_q_cat(1000)','from __main__ import so_q_cat')
>>> t1.timeit(number=10000000)
12.166618871951641
>>> t2.timeit(number=10000000)
5.7813972166853773
>>> t1.timeit(number=1)
1.103492206766532e-05
>>> t2.timeit(number=1)
8.5206360154188587e-06

>>> def so_q_tmp(n):
...  return "{d}{q}/{n}".format(d=DOMAIN,q=QUESTIONS,n=n)
...
>>> so_q_tmp(1000)
'http://stackoverflow.com/questions/1000'
>>> t3= timeit.Timer('so_q_tmp(1000)','from __main__ import so_q_tmp')
>>> t3.timeit(number=10000000)
14.564135316080637

>>> def so_q_join(n):
...  return ''.join([DOMAIN,QUESTIONS,'/',str(n)])
...
>>> so_q_join(1000)
'http://stackoverflow.com/questions/1000'
>>> t4= timeit.Timer('so_q_join(1000)','from __main__ import so_q_join')
>>> t4.timeit(number=10000000)
9.4431309007150048
55
Vinko Vrsalovic

Vergessen Sie nicht die benannte Substitution:

def so_question_uri_namedsub(q_num):
    return "%(domain)s%(questions)s/%(q_num)d" % locals()
23
too much php

Vorsicht bei der Verkettung von Zeichenketten in einer Schleife! Die Kosten für die Verkettung von Zeichenketten sind proportional zur Länge des Ergebnisses. Looping führt Sie direkt in das Land des N-Quadrats. Einige Sprachen optimieren die Verkettung mit der zuletzt zugewiesenen Zeichenfolge, es ist jedoch riskant, sich auf den Compiler zu verlassen, um Ihren quadratischen Algorithmus bis auf linear zu optimieren. Verwenden Sie am besten das Grundelement (join?), Das eine ganze Liste von Zeichenfolgen aufnimmt, eine einzelne Zuordnung vornimmt und sie alle auf einmal verkettet.

12
Norman Ramsey

"Da die Verkettung von Zeichenfolgen die Leistung erheblich gesteigert hat ..."

Wenn es auf die Leistung ankommt, ist dies gut zu wissen.

Leistungsprobleme, die ich gesehen habe, sind jedoch nie auf Zeichenfolgenoperationen zurückzuführen. Ich habe generell Probleme mit I/O, Sortieren und O (n2) Operationen sind die Engpässe.

Bis Zeichenfolgenoperationen die Leistungsbegrenzer sind, halte ich mich an Dinge, die offensichtlich sind. Meistens ist dies eine Substitution, wenn es sich um eine Zeile oder weniger handelt, eine Verkettung, wenn es sinnvoll ist, und ein Vorlagenwerkzeug (wie Mako), wenn es groß ist.

11
S.Lott

Was Sie verketten/interpolieren möchten und wie Sie das Ergebnis formatieren möchten, sollte Ihre Entscheidung beeinflussen.

  • Mit der Zeichenfolgeninterpolation können Sie problemlos Formatierungen hinzufügen. Tatsächlich hat Ihre String-Interpolationsversion nicht die gleiche Funktion wie Ihre Verkettungsversion. Tatsächlich wird vor dem Parameter q_num ein zusätzlicher Schrägstrich eingefügt. Um dasselbe zu tun, müssten Sie in diesem Beispiel return DOMAIN + QUESTIONS + "/" + str(q_num) schreiben.

  • Die Interpolation erleichtert das Formatieren von Zahlen. "%d of %d (%2.2f%%)" % (current, total, total/current) wäre in Verkettungsform viel weniger lesbar.

  • Die Verkettung ist nützlich, wenn Sie keine feste Anzahl von Elementen für die Zeichenfolge haben.

Beachten Sie auch, dass Python 2.6 eine neue Version der String-Interpolation einführt: String-Templating :

def so_question_uri_template(q_num):
    return "{domain}/{questions}/{num}".format(domain=DOMAIN,
                                               questions=QUESTIONS,
                                               num=q_num)

Das Templating von Strings soll eventuell die% -Interpolation ersetzen, aber das wird wohl noch eine ganze Weile so bleiben.

10
Tim Lesher

Ich habe gerade aus Neugier die Geschwindigkeit verschiedener String-Verkettungs-/Substitutionsmethoden getestet. Eine Google-Suche zu diesem Thema brachte mich hierher. Ich dachte, ich würde meine Testergebnisse veröffentlichen, in der Hoffnung, dass es jemandem bei der Entscheidung helfen könnte.

    import timeit
    def percent_():
            return "test %s, with number %s" % (1,2)

    def format_():
            return "test {}, with number {}".format(1,2)

    def format2_():
            return "test {1}, with number {0}".format(2,1)

    def concat_():
            return "test " + str(1) + ", with number " + str(2)

    def dotimers(func_list):
            # runs a single test for all functions in the list
            for func in func_list:
                    tmr = timeit.Timer(func)
                    res = tmr.timeit()
                    print "test " + func.func_name + ": " + str(res)

    def runtests(func_list, runs=5):
            # runs multiple tests for all functions in the list
            for i in range(runs):
                    print "----------- TEST #" + str(i + 1)
                    dotimers(func_list)

... Nachdem ich runtests((percent_, format_, format2_, concat_), runs=5) ausgeführt hatte, stellte ich fest, dass die% -Methode auf diesen kleinen Zeichenfolgen etwa doppelt so schnell war wie die anderen. Die concat-Methode war immer die langsamste (kaum). Beim Wechseln der Positionen in der format() -Methode gab es sehr kleine Unterschiede, aber das Wechseln der Positionen war immer mindestens 0,01 Sekunden langsamer als bei der normalen Formatmethode.

Probe der Testergebnisse:

    test concat_()  : 0.62  (0.61 to 0.63)
    test format_()  : 0.56  (consistently 0.56)
    test format2_() : 0.58  (0.57 to 0.59)
    test percent_() : 0.34  (0.33 to 0.35)

Ich habe diese ausgeführt, weil ich in meinen Skripten Zeichenfolgenverkettung verwende und mich gefragt habe, wie hoch die Kosten sind. Ich habe sie in verschiedenen Reihenfolgen ausgeführt, um sicherzustellen, dass nichts störte oder dass die Leistung als erster oder letzter besser wurde. Als Randnotiz habe ich einige längere String-Generatoren in Funktionen wie "%s" + ("a" * 1024) geworfen, und reguläres Concat war fast dreimal so schnell (1.1 vs. 2.8) wie die Funktionen format und % Methoden. Ich denke, es hängt von den Saiten und dem ab, was Sie erreichen wollen. Wenn es wirklich auf die Leistung ankommt, ist es möglicherweise besser, verschiedene Dinge auszuprobieren und zu testen. Ich neige dazu, die Lesbarkeit der Geschwindigkeit vorzuziehen, es sei denn, die Geschwindigkeit wird zum Problem, aber das bin nur ich. SO mochte mein Kopieren/Einfügen nicht, ich musste 8 Leerzeichen auf alles setzen, damit es richtig aussieht. Ich benutze normalerweise 4.

7
Cj Welborn

Denken Sie daran, stilistische Entscheidungen sind praktische Entscheidungen, wenn Sie jemals vorhaben, Ihren Code zu pflegen oder zu debuggen :-) Es gibt ein berühmtes Zitat von Knuth (möglicherweise zitiert Hoare?): "Wir sollten beispielsweise kleine Effizienzminderungen vergessen etwa 97% der Fälle: Vorzeitige Optimierung ist die Wurzel allen Übels. "

Solange Sie darauf achten, eine O(n) - Aufgabe nicht in eine O (n) zu verwandeln2) Aufgabe, ich würde mit dem gehen, was Sie am einfachsten zu verstehen finden ..

4
John Fouhy

Ich setze Substitution ein, wo immer ich kann. Ich verwende Verkettung nur, wenn ich eine Zeichenfolge in einer for-Schleife aufbaue.

0
Draemon