2015-11-13 19 views
7

Ist es ein guter Stil, Tupel anstelle von Listen für konstante Iterables auf Modulebene in Python zu verwenden? Zum Beispiel habe ich eine Liste von wichtigen Saiten an der Spitze meiner Datei, die ich in meinem Eingang suchen muß:Tupel vs Listen für Modulebenenkonstanten in Python?

IMPORTANT_STRINGS = [ 
    "Hello world!", 
    "Goodbye world!", 
    "Foo...", 
    # etc --- there are about 40 entries 
] 

IMPORTANT_STRINGS wird nie geändert werden, während mein Programm läuft.

Auf der einen Seite denke ich, dass Unveränderlichkeit gut ist und dass ich sollte unveränderlich Datenstrukturen, wann immer möglich bevorzugen, also sollte ich stattdessen ein Tupel verwenden.

Auf der anderen Seite, denke ich, dass Tupel mehr als nur unveränderliche Listen sind: Sie sind für heterogene Sammlungen, die verwendet werden sollten, wenn Sie Dinge wie Paare, Triples usw. passieren - Dinge fester Größe deren Größe wichtig ist für das, was sie sind. Ich denke auch nicht, dass ich jemals Python-Code in der freien Natur gesehen habe, die Tupel für Konstanten wie diese verwendet, und es sieht aus, um mein Auge wirklich seltsam zu sagen:

IMPORTANT_STRINGS = (
    "Hello world!", 
    etc 
) 
+2

Konstante impliziert Unveränderlichkeit, so würde ich persönlich ein Tupel verwenden ... das sagte ich bin ziemlich sicher, es gibt keine "Best Practice" für diese definiert so verwenden Sie, was Sie wollen mehr –

+0

Warum gruppieren Sie diese zusammen in irgendeiner Art von Struktur an alle? Werden Sie jemals über sie iterieren? Wirst du jemals auf sie per Index zugreifen (und wenn ja, ist das wirklich der beste Weg, um an sie heranzukommen?) Warum definierst du überhaupt String-Konstanten? Lange Sammlungen von String-Konstanten im Allgemeinen scheinen mir nur ein schlechter Code-Geruch zu sein, wobei das, was Sie wirklich wollen, eine Art Attribut für ein Objekt oder stattdessen Schlüsselwort-Argumente wären. Es ist ein Symptom von [stringly typed code] (http://c2.com/cgi/wiki?StringlyTyped). – ArtOfWarfare

+0

Betreffend herogenerous - Listen sollten aus allen Objekten des gleichen Typs bestehen. Tuples haben keine solchen Einschränkungen - sie können Objekte unterschiedlicher Art haben oder auch nicht. Aber da Ihre Variable 'WICHTIGES_STRINGEN' heißt, denke ich, dass es für den Benutzer schon ziemlich klar ist, dass die Werte innerhalb des Typs' string' sind, unabhängig vom Typ der Sammlung. – ArtOfWarfare

Antwort

4

Erstellen Sie ein Modul, rufen sie foo.py und legen Sie die folgenden Schritte aus:

FOO = 'a', 'b' 
BAR = ['a', 'b'] 

Jetzt sie importieren und sehen, wie sie in-Place-Operationen reagieren:

>>> import foo 
>>> from foo import FOO, BAR 
>>> FOO += 'c', 'd' 
>>> BAR += 'c', 'd' 
>>> FOO 
('a', 'b', 'c', 'd') 
>>> foo.FOO 
('a', 'b') 
>>> foo.BAR 
['a', 'b', 'c', 'd'] 

Wie wir sehen können FOO, das Tupel, bleibt in seinem ursprünglichen Zustand als die kanonische Sammlung im Modul foo. BAR auf der anderen Seite kann mutiert werden.

, die Sie bevorzugen sollten?

Es hängt davon ab, was Sie passieren soll, wenn andere Module die Sammlung zugreifen. In vielen Fällen möchten wir, dass andere Module zu einer kanonischen Liste hinzugefügt werden können. In einigen Fällen tun wir das nicht. Die Antwort ist, zu tun, was angesichts Ihrer Umstände und Zwecke und Absichten für Design und Verwendung angemessen ist.

In Ihrem Fall, sagen Sie:

WICHTIG STRINGS wird nie geändert werden, während mein Programm läuft.

Wenn sie nie sollten modifiziert werden, dann sind Tupel in Ordnung. Wenn Sie möchten, dass Ihr Code für andere nützlich ist, die möglicherweise Daten im selben Prozess freigeben müssen, sollten Sie eine Liste verwenden.

Sie erwähnen:

Ich denke, dass Tupel sind mehr als nur unveränderlich Listen: sie sind für heterogene Sammlungen, die verwendet werden sollten, wenn Sie um Dinge wie Paare vorbei sind, Dreier-, etc --- Dinge fester Größe, deren Größe wichtig ist für das, was sie sind.

Ich würde nicht zu sehr in der Heterogenität gefangen werden. Tupel sind im Wesentlichen unveränderbare Listen, und Listen können auch alle Arten von Objekten enthalten. Ja, feste Größe, aber das ist wirklich nur eine direkte Folge der Unveränderlichkeit.

Beachten Sie, dass die Möglichkeit, Listen wie oben gezeigt mit Tupeln zu erweitern, bedeutet, dass Sie im Allgemeinen mit Tupeln beginnen und dann bei Bedarf zu Listen wechseln können.

+0

Ich verstehe den Unterschied zwischen veränderlichen und unveränderlichen Datenstrukturen und warum ich unveränderliche bevorzugen sollte. Ich bin einfach verrückt, weil ich Python noch nie so geschrieben habe - wenn ich nur Listen verwende, wenn ich eine Veränderlichkeit brauche, würde ich Tupel anstelle von etwa 80% der Sammlungen verwenden, die ich derzeit verwende.Schreiben Sie eigentlich Code, der fast vollständig mit Tupeln gefüllt ist, indem Sie Listen nur dann verwenden, wenn dies absolut notwendig ist? –

+0

@PatrickCollins Ich benutze Tupel mehr als andere Python-Codierer (die Listen als die einzige Art von Python-Array zu behandeln scheinen). Ich benutze Pythons Duck-Typing und Abstract Base Class Checking, also wenn ich stattdessen eine Liste verwenden muss, bricht es meinen Code nicht, um zu wechseln. Meine Argumentation ist in der Regel mehr aus Gründen der Leistung als aus Sicherheitsgründen. –

+0

Ich akzeptiere diese Antwort, weil es die vollständigste ist, aber ich möchte feststellen, dass ich es unbefriedigend finde. Ich habe noch nie einen Code in der Wildnis gesehen, der in diesem Fall Tupel über Listen verwendet, und ich denke immer noch, dass er stilistisch sehr seltsam ist. Ich kann mir Python vorstellen, das Tupel konsequent über Listen verwendet und ich denke, es wäre in Ordnung, aber wenn Sie nicht an Ihrem eigenen persönlichen Projekt arbeiten, denke ich, dass dies mit den Erwartungen der anderen Entwickler in Ihrem Team kollidieren wird. Unveränderlichkeit ist wichtig und es ist großartig in Sprachen, die es gut unterstützen, aber das ist nicht Pythonic. –

3

ich für das Tupel gehen würde . Tupel sind schneller, unveränderbar und deshalb sicherer. Warum willst du einen veränderlichen Typ für etwas, das unveränderlich sein sollte?

Das Argument, dass „Tupel für heterogene Sammlungen sind“ hat keinen Sinn für mich. Listen können auch heterogene Elemente speichern. Die Annahme, dass Tupel = heterogen und Listen = homogen ist, ist nur eine Verallgemeinerung, normalerweise möchten Sie, dass eine Liste Elemente durchläuft und mit ihnen ähnlich arbeitet (wenn nicht genau in der gleichen Weise, zumindest in einer polymorphen Weise)

Tuples on Andererseits sind sie einer Struktur in dem Sinne etwas ähnlich, dass sie verwendet werden, um Werte zu speichern, die in dem Modell, das Sie codieren, eine Beziehung haben und auf diese Weise mit heterogenen Elementen verwandt sind, aber warum können sie nicht vom selben Typ sein? Zum Beispiel würde ein 3-dimensionaler Vektor als ein Tupel dargestellt werden (zumindest ist dies der intuitivste Weg), aber er besteht nur aus 3 Zahlen, sollten wir eine Liste verwenden, nur weil sie gleich sind?

+0

Ich denke, dass ich heterogen härter als ich sollte treffen, aber Vektoren sind anders - die Tatsache, dass sie N dimensional sind, ist ein wesentlicher Teil ihres Typs. Es ist bezeichnend, dass sie diese Struktur haben. Dies ist andererseits nur eine Ansammlung von ein paar Dingen, die zufällig statisch initialisiert werden, anstatt zur Laufzeit erstellt zu werden. Ich denke, 80% des Codes sind rein zufällig und 99% können einfach umgeschrieben werden, um rein zu sein. Ich habe noch nie Python-Code gesehen, der Tupel als Standard-Sammlung verwendet. Schreiben Sie Code wie diesen? –

1

Nur für ein Gegenargument ist __all__ eine Liste öffentlicher Objekte, die ein Modul exportieren, wenn: from <module> import * verwendet wird.

Dies ist im Grunde eine Sammlung von konstanten Strings auf Modulebene (wie Sie haben), ist aber als eine Liste in der Standardbibliothek implementiert. Ein Schnelltest bestätigt, dass ein tuple auch dafür funktioniert, aber überall ist es eine Liste.

+0

Durch die Wandlungsfähigkeit können Module direkt erweitert werden. Aus meiner Erfahrung in früheren Pythons muss es eine Liste sein, um die erwarteten Effekte zu erhalten, aber eine schnelle Überprüfung mit Python 3 zeigt, dass es dort keine Rolle spielt. –

+0

Interessant ... wie werden Module an Ort und Stelle erweitert? – Gerrat

+0

Ich benutze Extend im Sinne des Hinzufügens zur API, obwohl es eine einfache Sache ist, das '__all__' Tupel zu ersetzen, anstatt die Liste zu erweitern (was die mit' import * 'importierten Namen betrifft), sehe ich nicht jemand, der jemals das '__all__' eines anderen Moduls verwendet, indem er den Namen direkt importiert. –