2012-06-29 15 views
21

Ich benutze Python seit einiger Zeit und ich entdecke die "Pythonic" Art zu code. Ich verwende viele Tupel in meinem Code, die meisten von ihnen sind polar oder kartesische Positionen.Tuples Lesbarkeit: [0,0] vs (0,0)

fand ich mich das Schreiben:

window.set_pos([18,8]) 

statt dessen:

window.set_pos((18,8)) 

loszuwerden Doppel Klammer ich schwer zu lesen gefunden.

Es scheint, dass Python automatisch die Typkonvertierung von Liste zu Tupel durchführt, da mein Code ordnungsgemäß funktioniert.

Aber ist es ein guter Weg zu programmieren? Haben Sie einen Präsentationstipp, den ich verwenden könnte, um lesbaren Code zu schreiben?

Vielen Dank im Voraus für Ihre sicherlich aufschlussreiche Antworten.

+0

Ich mag die Art, wie Sie es geschrieben haben, scheint mehr gut definiert imo. – jamylak

+9

Python führt keine Typumwandlung von Liste zu Tupel durch. Dies ist [ente typing] (http://en.wikipedia.org/wiki/Duck_typing) in Aktion: vermutlich benötigt 'window.set_pos' eine Sequenz von zwei Items, aber nicht unbedingt ein 2-'Tuple' (ich sage vermutlich da ich nicht weiß, woher 'window.set_pos' stammt oder was es tut. – Chris

+9

Schreiben Sie die Funktion so um, dass sie zwei Argumente anstatt eines 2-Tupels verwendet. –

Antwort

25

Ich wäre vorsichtig zu entscheiden, Tupel zugunsten von Listen überall zu vermeiden. Haben Sie jemals das dis Modul verwendet? Sehen Sie, was Python auf der Bytecode-Ebene tut, wenn Sie eine Liste Verse machen ein Tupel machen:

>>> def f(): 
...  x = [1,2,3,4,5,6,7] 
...  return x 
... 
>>> def g(): 
...  x = (1,2,3,4,5,6,7) 
...  return x 
... 
>>> import dis 
>>> dis.dis(f) 
    2   0 LOAD_CONST    1 (1) 
       3 LOAD_CONST    2 (2) 
       6 LOAD_CONST    3 (3) 
       9 LOAD_CONST    4 (4) 
      12 LOAD_CONST    5 (5) 
      15 LOAD_CONST    6 (6) 
      18 LOAD_CONST    7 (7) 
      21 BUILD_LIST    7 
      24 STORE_FAST    0 (x) 

    3   27 LOAD_FAST    0 (x) 
      30 RETURN_VALUE  
>>> 
>>> 
>>> dis.dis(g) 
    2   0 LOAD_CONST    8 ((1, 2, 3, 4, 5, 6, 7)) 
       3 STORE_FAST    0 (x) 

    3   6 LOAD_FAST    0 (x) 
       9 RETURN_VALUE 

Obwohl es wahrscheinlich nie ein Problem in einer GUI-Anwendung (wie Ihr Beispiel zu sein scheint), aus Performance-Gründen Sie sollten darauf achten, dies überall in Ihrem Code zu tun.

+1

Vielen Dank, Sie haben mich überzeugt! Die Leistung ist mir sehr wichtig, da meine Anwendung keine GUI, sondern ein Spiel mit grafischer Benutzeroberfläche ist. Deine Bytecode-detaillierte Antwort ist sehr hilfreich, um zu verstehen, was im Hintergrund passiert (ich kannte das Dis-Modul nicht). –

+1

Ich habe nur die zwei Funktionen zeitlich abgestimmt: Die Listenversion dauert ca. verdoppeln Sie die Zeit als die Tupel-Version (2,1 vs 0,9 Sekunden für 10 Mio. Anrufe). Bei Sammlungen mit zwei Elementen sind die Unterschiede jedoch geringer: 1,6 vs. 0,9 Sekunden. –

+2

Ah, richtig - ich hatte vergessen, dass Tupel Literale [gefaltet] sind (http://stackoverflow.com/a/8068248/577088). Wenn Sie Literale (und keine aus Variablen konstruierten Tupel) übergeben, könnte dies einen großen Unterschied machen. – senderle

0

Wenn Sie die Tatsache hervorheben wollen, dass Ihre Parameter ein Tupel ist, können Sie es explizit konvertieren:

window.set_pot(tuple([18, 18])) 
+4

Das sieht viel schlechter aus. – jamylak

4

IMO die nur von Vorteil (18,8) über [18,8] besteht darin, dass ein Tupel Objekt unveränderlich ist und Sie können stellen Sie sicher, dass es nicht innerhalb der Funktion geändert wird, die es passiert, während [18,8] kann leicht geändert werden.

4

Python führt keine automatische Konvertierung von Liste zu Tupel durch, es sei denn, die Methode set_pos tut dies explizit. Tupel und Liste haben sehr ähnliche Protokolle, so dass sie innerhalb dieses Protokolls austauschbar sind. Sie können immer noch Dinge brechen, insbesondere weil das Tupel ein Unveränderliches ist, das gehashed werden kann, und eine Liste nicht.

Ihre Frage zu beantworten, nur

window.set_pos((18,18)) 

geeignete Räume mit Codierung Stil tun Wunder schreiben.

+4

PEP-8 rät davon ab, dies zu tun: http://www.python.org/dev/peps/pep-0008/#pet-peeves – jamylak

+1

@jamylak: einverstanden, und ich stimme dem PEP-Vorschlag zu, aber das ist etwas Besonderes Fall, der die Ausnahme wert sein könnte. –

+0

@jamylak Es wird nicht durch die Sprache erzwungen, was bedeutet, dass es nur ein Kodierungsstil ist, den der/die Autor (en) von Python gerne haben. Es ist nicht der Alles-Ende-aller Codierungsstil, und sollte nie als solcher genommen werden. Betrachte sie einfach als gute Richtlinien und sei bereit, sie zu brechen, wenn sie die Lesbarkeit verletzen - wie in diesem Fall. – Izkata

12

Sie sagen

Es scheint, dass Python automatisch die Typumwandlung von Liste tut

auf Tupel Das zweifelhaft ist. Da Listen und Tupel beide sequence types sind, implementieren sie beide viele der gleichen Verhaltensweisen, und die von Ihnen verwendete GUI-Bibliothek darf keines der Listen-Verhalten verwenden.

Es ist wahrscheinlich fein dies in vielen Fällen zu tun, aber beachten Sie, dass die Listen ein wenig mehr Platz als Tupel nehmen Sie:

>>> sys.getsizeof((1, 2)) 
72 
>>> sys.getsizeof([1, 2]) 
88 

und kann auf einige Dinge langsamer als Tupel sein:

>>> lst, tup = [1, 2], (1, 2) 
>>> def unpack(x): 
...  a, b = x 
...  
>>> %timeit unpack(tup) 
10000000 loops, best of 3: 163 ns per loop 
>>> %timeit unpack(lst) 
10000000 loops, best of 3: 172 ns per loop 

Dies sind sehr kleine Unterschiede, die bis Sie viel größere Maßstäbe erreichen wird keine Rolle - wie in Milliarden von Anrufen - s o die Abwägung könnte sich lohnen.

Dennoch sehe ich nicht, dass Leute das sehr oft tun. Es scheint ein guter Lesbarkeitstrick zu sein, aber unter bestimmten Umständen könnte es unerwartete Folgen haben. Wenn Sie beispielsweise eine Liste übergeben, die Sie später erneut verwenden möchten, müssen Sie darauf achten, sie nicht innerhalb der Funktion zu ändern. Schließlich, wie zu Recht darauf hinweist, neigen Tupel und Listen zu Mittelwert etwas andere Dinge; Wenn Sie sie auf unkonventionelle Weise verwenden, kann dies den Lesbarkeitsschub zunichte machen, den Sie suchen.

+0

Vielen Dank für Ihre präzise Antwort! Ich weiß, dass es ein wenig seltsam scheint, aber ich bin begeistert von der Idee, ein unpassendes Objekt nur aus Lesbarkeitsgründen zu verwenden. Meine "set_pos" -Methode entpackt das Argument einfach in zwei Variablen, wird aber die meiste Zeit innerhalb einer Schleife verwendet und ich kümmere mich um Performance-Probleme. Sind 14 Ns wichtig? –

+0

Nein, 14ns spielt keine Rolle, wenn es um die Position Ihres Fensters geht. –

8

Ich bezweifle ernsthaft, dass Tupel vs. Listen merkbaren Unterschied in der Leistung in Ihrem Fall machen. Führen Sie keine Mikrooptimierungen durch, es sei denn, Ihr Profiler sagt dies. Lesbarkeit ist eine Priorität.

list und tuple sind beide sequence types.

Semantisch Tupel könnten vorzuziehen sein (siehe Tuples have structure, lists have order). Position ist ein einzelnes Objekt mit x, y-Attributen.

Visuell Listen könnten in diesem Fall einfacher zu lesen sein.

Was auch immer Sie gerade wählen konsistent sein.

prüfen, ob window unterstützt die folgenden:

window.pos = 18, 8 

Ein möglicher Weg, es zu implementieren, ist die pos eine property zu machen und set_pos() als Setter binden.

+2

+1 für die Semantik von Tupel vs. Listen, die fast immer der entscheidende Faktor sein sollte. – FogleBird

Verwandte Themen