2016-01-10 10 views
9

Soweit ich es verstehe, sind Tupel und Strings unveränderlich, um Optimierungen wie die Wiederverwendung von Speicher zu ermöglichen, der sich nicht ändert. Eine offensichtliche Optimierung, bei der Tupel-Segmente sich auf den gleichen Speicher wie das ursprüngliche Tupel beziehen, ist jedoch in Python nicht enthalten.Da Tupel unveränderlich sind, warum macht das Schneiden sie eine Kopie statt einer Ansicht?

Ich weiß, dass diese Optimierung, weil nicht enthalten ist, wenn ich Zeit die folgende Funktion, die benötigten Zeit geht wie O (n^2) anstelle von O (n), so voll Kopieren stattfindet:

def test(n): 
    tup = tuple(range(n)) 
    for i in xrange(n): 
     tup[0:i] 

Gibt es ein Verhalten von Python, das sich ändern würde, wenn diese Optimierung implementiert wäre? Gibt es einen Leistungsvorteil beim Kopieren, selbst wenn das Original unveränderlich ist?

+8

Manchmal lautet die Antwort "weil sich noch niemand die Zeit genommen hat, es vollständig umzusetzen". –

+1

Reichen Sie eine Pull-Anforderung ein. –

+0

Es kann ein Kompromiss sein zwischen dem Reduzieren des Kopierumfangs, wie Sie darauf hinweisen, und dem Reduzieren der Anzahl der Referenzzählungen auf das ursprüngliche Tupel, so dass es früher Garbage Collected sein kann. – cr3

Antwort

1

Denken Sie an view über etwas, das dem entspricht, was numpy tut? Ich weiß, wie und warum numpy das tut.

A numpy ist ein Objekt mit Form- und D-Typ-Informationen sowie einem Datenpuffer. Sie können diese Informationen in der __array_interface__-Eigenschaft sehen. Ein view ist ein neues numpy-Objekt mit einem eigenen Shape-Attribut, aber mit einem neuen Datenpufferzeiger, der auf eine Stelle im Quellpuffer verweist. Es hat auch eine Flagge, die sagt "Ich besitze nicht den Puffer". numpy behält auch seine eigene Referenzzählung bei, so dass der Datenpuffer nicht zerstört wird, wenn das ursprüngliche (Eigentümer-) Array gelöscht wird (und Garbage Collected).

Diese Verwendung von Ansichten kann viel Zeit sparen, besonders bei sehr großen Arrays (Fragen zu Speicherfehlern sind bei SO üblich). Sichten erlauben auch verschiedene dtype, so dass ein Datenpuffer bei 4 Byte Ganzzahlen oder 1 Bytes Zeichen usw. angezeigt werden kann.

Wie würde dies für Tupel gelten? Meine Vermutung ist, dass es viel zusätzliches Gepäck erfordern würde. Ein Tupel besteht aus einem festen Satz von Objektzeigern - wahrscheinlich einem C-Array. Eine Ansicht würde dasselbe Array verwenden, aber mit eigenen Start- und Endmarkierungen (Zeigern und/oder Längen). Was ist mit Flags teilen? Müllabfuhr?

Und was ist die typische Größe und Verwendung von Tupeln? Eine häufige Verwendung von Tupeln besteht darin, Argumente an eine Funktion zu übergeben. Meine Vermutung ist, dass die meisten Tupel in einem typischen Python-Lauf klein sind - 0, 1 oder 2 Elemente. Scheiben sind erlaubt, aber sind sie sehr üblich? Auf kleinen Tupeln oder sehr großen?

Würden unbeabsichtigte Konsequenzen für die Darstellung von Tupelscheiben entstehen (im angeschlagenen Sinn)? Die Unterscheidung zwischen Ansichten und Kopien ist eine der schwierigsten Dinge für numpy Benutzer zu erfassen. Da ein Tupel unveränderlich sein soll - das heißt, die Zeiger im Tupel können nicht geändert werden - ist es möglich, dass Implementierungsansichten für Benutzer unsichtbar sind. Aber ich frage mich immer noch.

Es kann am sinnvollsten sein, diese Idee auf einem Zweig der PyPy Version zu versuchen - es sei denn, Sie möchten wirklich in Cpython Code eintauchen. Oder als benutzerdefinierte Klasse mit Cython.

Verwandte Themen