Das hat mich immer verwirrt. Es scheint, als wäre das schöner:
my_list = ["Hello", "world"]
print my_list.join("-")
# Produce: "Hello-world"
Als das:
my_list = ["Hello", "world"]
print "-".join(my_list)
# Produce: "Hello-world"
Gibt es einen bestimmten Grund dafür?
Es liegt daran, dass jedes iterative Element verbunden werden kann, nicht nur Listen, sondern das Ergebnis und der "Joiner" sind immer Zeichenfolgen.
Z.B:
import urllib2
print '\n############\n'.join(
urllib2.urlopen('http://data.stackexchange.com/users/7095'))
Dies wurde im Thread String methods ... finally im Python-Dev-Archiv besprochen und von Guido akzeptiert. Dieser Thread begann im Juni 1999 und str.join
wurde in Python 1.6 aufgenommen, das im September 2000 veröffentlicht wurde (und Unicode unterstützte). Python 2.0 (unterstützte str
Methoden einschließlich join
) wurde im Oktober 2000 veröffentlicht.
str.join(seq)
seq.join(str)
seq.reduce(str)
join
als integrierte Funktionlist
s, Tuple
s, sondern alle Sequenzen/Iterables unterstützen.seq.reduce(str)
ist für Neulinge schwierig.seq.join(str)
führt eine unerwartete Abhängigkeit von Sequenzen zu str/unicode ein.join()
als integrierte Funktion würde nur bestimmte Datentypen unterstützen. Ein eingebauter Namespace ist also nicht gut. Wenn join()
viele Datentypen unterstützt, ist die Erstellung einer optimierten Implementierung schwierig. Wenn die Implementierung mit der __add__
-Methode erfolgt, ist sie O (n²).sep
) sollte nicht weggelassen werden. Explizit ist besser als implizit.In diesem Thread werden keine weiteren Gründe aufgeführt.
Hier sind einige zusätzliche Gedanken (meine eigenen und die meines Freundes):
Guidos Entscheidung wird in einer historischen Mail aufgezeichnet, die über str.join(seq)
entscheidet:
Komisch, aber es scheint richtig! Barry, mach schon ...
- Guido van Rossum
Befindet sich die Methode join()
in der Zeichenfolgenklasse anstelle der Listenklasse?
Ich bin damit einverstanden, dass es lustig aussieht.
Siehe http://www.faqs.org/docs/diveintopython/odbchelper_join.html :
Historischer Hinweis. Als ich Python zum ersten Mal lernte, erwartete ich, dass join eine Methode einer Liste ist, bei der das Trennzeichen als Argument verwendet wird. Vielen Menschen geht es genauso, und hinter der Join-Methode verbirgt sich eine Geschichte. Vor Python 1.6 hatten Strings nicht alle diese nützlichen Methoden. Es gab ein separates Zeichenkettenmodul, das alle Zeichenkettenfunktionen enthielt. Für jede Funktion wurde als erstes Argument eine Zeichenfolge verwendet. Die Funktionen wurden als wichtig genug erachtet, um sie auf die Zeichenfolgen selbst zu übertragen, was für Funktionen wie Lower, Upper und Split Sinn machte. Aber viele Hardcore-ProgrammiererPythonhaben Einwände gegen die neue Join-Methode erhoben und argumentiert, dass sie stattdessen eine Methode der Liste sein sollte oder dass sie sich überhaupt nicht bewegen sollte, sondern einfach ein Teil der alten Zeichenfolge bleiben sollte Modul (das noch viele nützliche Dinge enthält). Ich verwende ausschließlich die neue Join-Methode, aber Sie werden sehen, dass Code in beide Richtungen geschrieben wurde. Wenn Sie das wirklich stört, können Sie stattdessen die alte Funktion string.join verwenden.
--- Mark Pilgrim, tauche ein in Python
Ich stimme zu, dass es zunächst nicht intuitiv ist, aber es gibt einen guten Grund. Join kann keine Methode einer Liste sein, weil:
Es gibt zwei Join-Methoden (Python 3.0):
>>> b"".join
<built-in method join of bytes object at 0x00A46800>
>>> "".join
<built-in method join of str object at 0x00A28D40>
Wenn join eine Methode einer Liste wäre, müsste sie ihre Argumente prüfen, um zu entscheiden, welche von ihnen aufgerufen werden soll. Und Sie können nicht Byte und Str zusammenfügen, daher macht die Art und Weise, wie sie es jetzt haben, Sinn.
Warum ist es
string.join(list)
anstelle vonlist.join(string)
?
Dies liegt daran, dass join
eine "String" -Methode ist! Es wird eine Zeichenfolge aus einer beliebigen iterablen Datei erstellt. Wenn wir die Methode auf Listen festhalten, wie sieht es dann aus, wenn es iterables gibt, die keine Listen sind?
Was ist, wenn Sie ein Tupel von Zeichenfolgen haben? Wenn dies eine list
Methode wäre, müssten Sie jeden solchen Iterator von Zeichenketten als list
umwandeln, bevor Sie die Elemente zu einer einzigen Zeichenkette zusammenfügen könnten! Zum Beispiel:
some_strings = ('foo', 'bar', 'baz')
Lassen Sie uns unsere eigene List-Join-Methode rollen:
class OurList(list):
def join(self, s):
return s.join(self)
Beachten Sie, dass wir zunächst aus jedem Iterationsschritt eine Liste erstellen müssen, um die Zeichenfolgen in diesem Iterationsschritt zu verknüpfen, wodurch sowohl Speicher als auch Rechenleistung verschwendet werden:
>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'
Wir müssen also einen zusätzlichen Schritt hinzufügen, um unsere Listenmethode zu verwenden, anstatt nur die eingebaute Zeichenfolgenmethode zu verwenden:
>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'
Der Algorithmus Python, der zum Erstellen des endgültigen Strings mit str.join
verwendet wird, muss das Iterable tatsächlich zweimal durchlaufen. Wenn Sie ihm also einen Generatorausdruck bereitstellen, muss er es zuerst in einer Liste materialisieren kann die endgültige Zeichenfolge erstellen.
Während das Weitergeben von Generatoren normalerweise besser ist als das Verstehen von Listen, ist str.join
eine Ausnahme:
>>> import timeit
>>> min(timeit.repeat(lambda: ''.join(str(i) for i in range(10) if i)))
3.839168446022086
>>> min(timeit.repeat(lambda: ''.join([str(i) for i in range(10) if i])))
3.339879313018173
Trotzdem ist die str.join
-Operation semantisch immer noch eine "String" -Operation, daher ist es immer noch sinnvoll, sie für das str
-Objekt zu haben als für verschiedene Iterables.
Betrachten Sie es als die natürliche orthogonale Operation zum Teilen.
Ich verstehe, warum es auf alles Iterable anwendbar ist und so nicht einfach implementiert werden kann nur auf Liste.
Aus Gründen der Lesbarkeit würde ich es gerne in der Sprache sehen, aber ich denke nicht, dass dies tatsächlich machbar ist. Wenn es sich bei der Iterabilität um eine Schnittstelle handeln würde, könnte sie der Schnittstelle hinzugefügt werden, dies ist jedoch nur eine Konvention, und es gibt keinen zentralen Weg dazu füge es der Menge der Dinge hinzu, die iterabel sind.
In erster Linie, weil das Ergebnis von someString.join()
eine Zeichenfolge ist.
Die Sequenz (Liste oder Tupel oder was auch immer) erscheint nicht im Ergebnis, nur eine Zeichenfolge. Da das Ergebnis eine Zeichenfolge ist, ist es als Methode einer Zeichenfolge sinnvoll.
-
in "-". Join (my_list) gibt an, dass Sie eine Liste aus dem Verbinden von Elementen in eine Zeichenfolge konvertieren. Dies ist ergebnisorientiert (nur zum leichteren Speichern und Verstehen).
Ich erstelle ein ausführliches Cheatsheet von Methods_of_string als Referenz.
string_methonds_44 = {
'convert': ['join','split', 'rsplit','splitlines', 'partition', 'rpartition'],
'edit': ['replace', 'lstrip', 'rstrip', 'strip'],
'search': ['endswith', 'startswith', 'count', 'index', 'find','rindex', 'rfind',],
'condition': ['isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isnumeric','isidentifier',
'islower','istitle', 'isupper','isprintable', 'isspace', ],
'text': ['lower', 'upper', 'capitalize', 'title', 'swapcase',
'center', 'ljust', 'rjust', 'zfill', 'expandtabs','casefold'],
'encode': ['translate', 'maketrans', 'encode'],
'format': ['format', 'format_map']}
Beides ist nicht schön.
string.join (xs, delimit) bedeutet, dass das Zeichenfolgenmodul das Vorhandensein einer Liste kennt, von der es nichts weiß, da das Zeichenfolgenmodul nur mit Zeichenfolgen arbeitet.
list.join (delimit) ist ein bisschen netter, weil wir es so gewohnt sind, dass Strings ein grundlegender Typ sind (und das sind sie auch in der Sprache). Dies bedeutet jedoch, dass der Join dynamisch ausgelöst werden muss, da im beliebigen Kontext von a.split("\n")
der python -Compiler möglicherweise nicht weiß, was ein ist, und nachschlagen muss (analog zu vtable lookup). Das ist teuer, wenn Sie es oft tun.
wenn der python -Runtime-Compiler weiß, dass list ein integriertes Modul ist, kann er die dynamische Suche überspringen und die Absicht direkt in den Bytecode codieren, während er andernfalls "join" von "a" dynamisch auflösen muss. Dies kann mehrere Vererbungsebenen pro Aufruf umfassen (da sich die Bedeutung von Join zwischen den Aufrufen möglicherweise geändert hat, da python eine dynamische Sprache ist).
leider ist dies der ultimative Fehler der Abstraktion; Unabhängig davon, für welche Abstraktion Sie sich entscheiden, ist Ihre Abstraktion nur im Kontext des Problems sinnvoll, das Sie lösen möchten, und als solches können Sie niemals eine konsistente Abstraktion erhalten, die nicht mit den zugrunde liegenden Ideologien unvereinbar ist, wenn Sie anfangen, sie zusammenzufügen zusammen, ohne sie in eine Ansicht zu hüllen, die mit Ihrer Ideologie vereinbar ist. Wenn Sie dies wissen, ist der Ansatz von Python flexibler, da er billiger ist. Es liegt an Ihnen, mehr zu bezahlen, damit er "schöner" aussieht, entweder indem Sie Ihren eigenen Wrapper oder Ihren eigenen Präprozessor erstellen.