2009-07-19 5 views
15

Ich habe festgestellt, dass ich einen Tausch in Python durchführen muss und ich schreibe so etwas.Pythonic Swap?

arr[first], arr[second] = arr[second], arr[first] 

Ich nehme an, das ist nicht so pythonisch. Weiß jemand, wie man einen Tausch in Python elegent macht?

EDIT: denke ich, ein weiteres Beispiel meine Zweifel zeigen

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA] 

ist dies die einzige verfügbare Lösung für die Auslagerung in Python? Ich habe viel gesucht, aber nicht eine nette Antwort finden ...

+0

Was magst du nicht? Was stimmt damit nicht? Was magst du gerne kürzer? Könnten Sie Pseudo-Code für das bereitstellen, was Ihrer Meinung nach besser wäre? –

+2

Es ist eine schreckliche Art, einen Tausch zu schreiben und jeden Ausdruck wiederholen zu müssen, aber es ist das Beste, was Python tun kann. C++'s Swap (a, b) ist die saubere, nicht-repetitive Art, Swaps zu machen, aber Python unterstützt diese indirekte Ebene nicht, also kann es das nicht tun. Nur etwas zum Leben; Jede Sprache hat ihre Grenzen, und das ist eine Nebensache. –

Antwort

14

Das einzige, was ich in Ihrem Beispiel-Code ändern könnte: wenn Sie etwas lange Namen wie self.memberlist über verwenden werden Noch einmal, es ist oft besser lesbar, wenn Sie es zuerst einem kürzeren Namen zuordnen ("zuweisen"). So zum Beispiel statt der langen, schwer zu lesen:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA] 

Sie könnten Code:

L = self.memberlist 
L[someindexA], L[someindexB] = L[someindexB], L[someindexA] 

Denken Sie daran, dass Python by-Nachschlagewerken so L genau das gleiche Objekt wie self.memberlist bezieht, KEINE Kopie (aus dem gleichen Grund ist die Zuweisung extrem schnell, egal wie lange die Liste ist, weil sie sowieso nicht kopiert wird - es ist nur eine weitere Referenz).

Ich denke nicht weiter Komplikation gerechtfertigt ist, obwohl natürlich einige Phantasie diejenigen leicht konzipiert werden könnten, wie zum Beispiel (für a, b „normalen“ Indizes >=0):

def slicer(a, b): 
    return slice(a, b+cmp(b,a), b-a), slice(b, a+cmp(a,b), a-b) 

back, forth = slicer(someindexA, someindexB) 
self.memberlist[back] = self.memberlist[forth] 

Ich denke, Bezifferung aus dieser Art von "fortgeschrittenen" Anwendungen ist eine nette Einbildung, nützliche geistige Übung, und viel Spaß - ich empfehle interessierten Lesern, sobald die allgemeine Idee klar ist, konzentrieren sich auf die Rolle dieser +cmp und wie sie Dinge für die Arbeit machen drei Möglichkeiten (a> b, a < b, a == b) [[nicht für negative Indizes, obwohl - warum nicht, und wie würde Slicer ändern müssen, um das zu beheben?]]. Aber die Verwendung solch einer ausgeklügelten Herangehensweise im Produktionscode wäre im Allgemeinen übertrieben und ziemlich unberechtigt, wodurch die Dinge trüber und schwieriger zu pflegen wären als der einfache und geradlinige Ansatz.

Denken Sie daran, simple is better than complex!

16
a, b = b, a 

Is a perfectly Pythonic idiom. Es ist kurz und lesbar, solange Ihre Variablennamen kurz genug sind.

+0

http://www.google.co.il/search?q=python+swap&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a –

1

Es ist schwer vorstellbar, wie es eleganter gemacht werden könnte: mit einer hypothetischen eingebauten Funktion ... swap_sequence_elements(arr, first, second) elegant? vielleicht, aber das ist in YAGGI-Gebiet - Sie werden es nicht bekommen ;-) - und der Funktionsaufruf-Overhead würde Sie davon abbringen, es selbst zu implementieren.

Was Sie haben, ist viel eleganter als die Alternative in-line Art und Weise: (! Bonus)

temp = arr[first] 
arr[first] = arr[second] 
arr[second] = temp 

und ist schneller zu (auf der nicht unvernünftig Annahme, dass ein Bytecode ROT_TWO ist schneller als ein LOAD_FAST Plus a STORE_FAST).

1

a, b = b, a ist etwa so kurz wie Sie bekommen, ist es nur drei Zeichen ist (abgesehen von den Variablennamen) .. Es ist ungefähr so, wie Sie Python'y

Eine Alternative ist der üblicher Nutzungs- bekommen a-temp-Variable:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA] 

..becomes ..

temp = self.memberlist[someindexB] 
self.memberlist[someindexB] = self.memberlist[someindexA] 
self.memberlist[someindexA] = temp 

..welche ich denke, messier und weniger "offensichtlich"

Eine weitere Möglichkeit, die vielleicht ein bisschen besser lesbar mit langen Variablennamen ist:

a, b = self.memberlist[someindexA], self.memberlist[someindexB] 
self.memberlist[someindexA], self.memberlist[someindexB] = b, a 
-1

Ich nehme an, Sie Vorteil der Schritt Argument von Slice-Notation, so etwas zu tun nehmen könnte:

myArr [2] = myArr [2] [:: - 1]

I‘ Ich bin mir nicht sicher, ob das klarer oder pythischer ist ...