Wie gebe ich mehrere Werte von einer Funktion zurück? [geschlossen]

1067

Die kanonische Methode, mehrere Werte in Sprachen zurückzugeben, die dies unterstützen, ist häufig ein Tupeln .

Option: Verwenden eines Tupels

Betrachten Sie dieses triviale Beispiel:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0, y1, y2)

Dies wird jedoch schnell problematisch, wenn die Anzahl der zurückgegebenen Werte zunimmt. Was ist, wenn Sie vier oder fünf Werte zurückgeben möchten? Sicher, Sie könnten sie weiter tupeln, aber es wird leicht zu vergessen, welcher Wert wo ist. Es ist auch ziemlich hässlich, sie auszupacken, wo immer Sie sie erhalten möchten.

Option: Verwenden eines Wörterbuchs

Der nächste logische Schritt scheint darin zu bestehen, eine Art "Datensatznotation" einzuführen. In Python ist der offensichtliche Weg, dies zu tun, mittels a dict.

Folgendes berücksichtigen:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0': y0, 'y1': y1 ,'y2': y2}

(Um ganz klar zu sein, y0, y1 und y2 sind nur als abstrakte Bezeichner gedacht. Wie bereits erwähnt, würden Sie in der Praxis aussagekräftige Bezeichner verwenden.)

Jetzt haben wir einen Mechanismus, mit dem wir ein bestimmtes Mitglied des zurückgegebenen Objekts projizieren können. Zum Beispiel,

result['y0']

Option: Verwenden einer Klasse

Es gibt jedoch eine andere Option. Wir könnten stattdessen eine spezialisierte Struktur zurückgeben. Ich habe dies im Kontext von Python gerahmt, aber ich bin sicher, dass es auch für andere Sprachen gilt. Wenn Sie in C arbeiten, ist dies möglicherweise Ihre einzige Option. Hier geht:

class ReturnValue:
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return ReturnValue(y0, y1, y2)

In Python sind sich die beiden vorherigen in Bezug auf die Installation vielleicht sehr ähnlich - schließlich handelt es sich { y0, y1, y2 }nur um Einträge im internen Bereich __dict__des ReturnValue.

Es gibt eine zusätzliche Funktion, die Python für winzige Objekte bereitstellt, das __slots__Attribut. Die Klasse könnte ausgedrückt werden als:

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

Aus dem Python-Referenzhandbuch :

Die __slots__Deklaration verwendet eine Folge von Instanzvariablen und reserviert in jeder Instanz gerade genug Speicherplatz, um einen Wert für jede Variable aufzunehmen. Speicherplatz wird gespart, da __dict__nicht für jede Instanz erstellt wird.

Option: Verwenden einer Datenklasse (Python 3.7+)

Geben Sie mit den neuen Datenklassen von Python 3.7 eine Klasse mit automatisch hinzugefügten speziellen Methoden, Eingaben und anderen nützlichen Tools zurück:

@dataclass
class Returnvalue:
    y0: int
    y1: float
    y3: int

def total_cost(x):
    y0 = x + 1
    y1 = x * 3
    y2 = y0 ** y3
    return ReturnValue(y0, y1, y2)

Option: Verwenden einer Liste

Ein weiterer Vorschlag, den ich übersehen hatte, stammt von Bill the Lizard:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

Dies ist jedoch meine am wenigsten bevorzugte Methode. Ich glaube, ich bin durch die Begegnung mit Haskell in Mitleidenschaft gezogen, aber die Idee von Listen mit gemischten Typen hat sich für mich immer unangenehm angefühlt. In diesem speziellen Beispiel ist die Liste kein gemischter Typ, aber es könnte denkbar sein.

Eine Liste, die auf diese Weise verwendet wird, hat, soweit ich das beurteilen kann, wirklich nichts mit dem Tupel zu tun. Der einzige wirkliche Unterschied zwischen Listen und Tupeln in Python besteht darin, dass Listen veränderlich sind , Tupel jedoch nicht.

Ich persönlich neige dazu, die Konventionen aus der funktionalen Programmierung zu übernehmen: Verwenden Sie Listen für eine beliebige Anzahl von Elementen desselben Typs und Tupel für eine feste Anzahl von Elementen eines vorgegebenen Typs.

Frage

Nach der langen Präambel kommt die unvermeidliche Frage. Welche Methode (denkst du) ist die beste?

saffsd
quelle
10
In y3Ihren hervorragenden Beispielen verwenden Sie eine Variable , aber wenn y3 nicht als global deklariert ist, würde dies NameError: global name 'y3' is not definedmöglicherweise nur eine Verwendung ergeben 3?
Hetepeperfan
11
Viele großartige Fragen mit großartigen Antworten werden geschlossen, da das Schlüsselwort "Meinung" entsteht. Man könnte argumentieren, dass die gesamte SO auf einer Meinung basiert, aber die Meinung basiert auf Fakten, Referenzen und spezifischem Fachwissen. Nur weil jemand fragt, "was Ihrer Meinung nach am besten ist", heißt das nicht, dass er nach persönlichen Meinungen fragt, die von Fakten, Referenzen und spezifischem Fachwissen aus der realen Welt abstrahiert sind. Sie fragen mit ziemlicher Sicherheit nach genau dieser Art von Meinung, die gründlich auf den Fakten, Referenzen und spezifischen Fachkenntnissen basiert und mit diesen dokumentiert ist, die die Person zur Bildung der Meinung verwendet hat.
NeilG
@hetepeperfan Sie müssen 3 nicht ändern, und y3 wird auch nicht global definiert. Sie können auch einen lokalen Namen verwenden y3, der den gleichen Job erledigt .
Okie

Antworten:

637

Zu diesem Zweck wurden in 2.6 benannte Tupel hinzugefügt. Siehe auch os.stat für ein ähnliches eingebautes Beispiel.

>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2

In neueren Versionen von Python 3 (3.6+, glaube ich) hat die neue typingBibliothek die NamedTupleKlasse erhalten, um benannte Tupel einfacher zu erstellen und leistungsfähiger zu machen. Beim Erben von typing.NamedTuplekönnen Sie Dokumentzeichenfolgen, Standardwerte und Typanmerkungen verwenden.

Beispiel (aus den Dokumenten):

class Employee(NamedTuple):  # inherit from typing.NamedTuple
    name: str
    id: int = 3  # default value

employee = Employee('Guido')
assert employee.id == 3
A. Coady
quelle
68
Dies ist nur eine richtige Antwort, da dies die einzige kanonische Struktur ist, die das OP nicht berücksichtigt hat, und weil es sein Problem der Verwaltung langer Tupel angeht. Sollte als akzeptiert markiert werden.
Luftangriff
7
Nun, die Entwurfsgründe dafür namedtuplesind ein geringerer Speicherbedarf für Massenergebnisse (lange Listen von Tupeln, z. B. Ergebnisse von DB-Abfragen). Für einzelne Elemente (wenn die betreffende Funktion nicht oft aufgerufen wird) sind Wörterbücher und Klassen ebenfalls in Ordnung. Aber Namedtuples sind auch in diesem Fall eine schöne Lösung.
Lutz Prechelt
8
@wom: Tu das nicht. Python unternimmt keine Anstrengungen, um namedtupleDefinitionen zu eindeutig zu machen (jeder Aufruf erstellt eine neue). Das Erstellen der namedtupleKlasse ist sowohl in der CPU als auch im Speicher relativ teuer, und alle Klassendefinitionen beinhalten an sich zyklische Referenzen (bei CPython warten Sie also auf einen zyklischen GC-Lauf für ihre Freilassung). Dies macht es auch für pickledie Klasse unmöglich (und daher multiprocessingin den meisten Fällen unmöglich, Instanzen mit zu verwenden ). Jede Erstellung der Klasse auf meinem 3.6.4 x64 verbraucht ~ 0,337 ms und belegt knapp 1 KB Speicher, wodurch alle Instanzeinsparungen zunichte gemacht werden.
ShadowRanger
3
Ich werde bemerken, dass Python 3.7 die Geschwindigkeit beim Erstellen neuer namedtupleKlassen verbessert hat . Die CPU-Kosten sinken ungefähr um den Faktor 4 , aber sie sind immer noch ungefähr 1000x höher als die Kosten für die Erstellung einer Instanz, und die Speicherkosten für jede Klasse bleiben hoch (ich habe mich in meinem letzten Kommentar zu "unter 1 KB" geirrt). Für die Klasse _sourcebeträgt sie in der Regel 1,5 KB ( _sourcewird in 3.7 entfernt, sodass sie wahrscheinlich näher an der ursprünglichen Behauptung von knapp 1 KB pro Klassenerstellung liegt).
ShadowRanger
4
@SergeStroobandt - Dies ist Teil der Standardbibliothek, nur keine eingebaute. Sie müssen sich keine Sorgen machen, dass es möglicherweise nicht auf einem anderen System mit Python> = 2.6 installiert wird. Oder widersprechen Sie einfach der zusätzlichen Codezeile?
Justin
234

Für kleine Projekte finde ich es am einfachsten, mit Tupeln zu arbeiten. Wenn das zu schwierig wird (und nicht vorher), fange ich an, Dinge in logische Strukturen zu gruppieren. Ich denke jedoch, dass Ihre vorgeschlagene Verwendung von Wörterbüchern und ReturnValueObjekten falsch (oder zu simpel) ist.

Wiederkehrende ein Wörterbuch mit den Tasten "y0", "y1", "y2"etc. bietet keinen Vorteil gegenüber Tupel. Zurückgeben einer ReturnValueInstanz mit Eigenschaften .y0, .y1, .y2etc. bietet keinen Vorteil gegenüber Tupeln entweder. Sie müssen anfangen, Dinge zu benennen, wenn Sie irgendwohin wollen, und Sie können dies trotzdem mit Tupeln tun:

def get_image_data(filename):
    [snip]
    return size, (format, version, compression), (width,height)

size, type, dimensions = get_image_data(x)

IMHO ist die einzig gute Technik jenseits von Tupeln die Rückgabe realer Objekte mit geeigneten Methoden und Eigenschaften, wie Sie sie von re.match()oder erhalten open(file).

zu viel php
quelle
6
Frage - gibt es einen Unterschied zwischen size, type, dimensions = getImageData(x)und (size, type, dimensions) = getImageData(x)? Dh, macht das Umschließen der linken Seite einer Tupelaufgabe einen Unterschied?
Reb.Cabin
11
@ Reb.Cabin Es gibt keinen Unterschied. Tupel wird durch Komma identifiziert und die Verwendung von Klammern dient nur dazu, Dinge zu gruppieren. Zum Beispiel (1)ist ein int while (1,)oder 1,ein Tupel.
Phil
19
Betreff "Das Zurückgeben eines Wörterbuchs mit den Schlüsseln y0, y1, y2 usw. bietet keinen Vorteil gegenüber Tupeln": Das Wörterbuch hat den Vorteil, dass Sie dem zurückgegebenen Wörterbuch Felder hinzufügen können, ohne vorhandenen Code zu beschädigen.
Ostrokach
Zu "Das Zurückgeben eines Wörterbuchs mit den Schlüsseln y0, y1, y2 usw. bietet keinen Vorteil gegenüber Tupeln": Es ist außerdem besser lesbar und weniger fehleranfällig, wenn Sie auf die Daten zugreifen, die auf dem Namen und nicht auf der Position basieren.
Denis Dollfus
204

Viele der Antworten deuten darauf hin, dass Sie eine Sammlung wie ein Wörterbuch oder eine Liste zurückgeben müssen. Sie können die zusätzliche Syntax weglassen und die durch Kommas getrennten Rückgabewerte einfach ausschreiben. Hinweis: Dies gibt technisch ein Tupel zurück.

def f():
    return True, False
x, y = f()
print(x)
print(y)

gibt:

True
False
Joseph Hansen
quelle
24
Sie geben immer noch eine Sammlung zurück. Es ist ein Tupel. Ich bevorzuge Klammern, um es deutlicher zu machen. Versuchen Sie Folgendes: type(f())kehrt zurück <class 'tuple'>.
Igor
20
@Igor: Es gibt keinen Grund, den tupleAspekt explizit zu machen . Es ist nicht wirklich wichtig, dass Sie a zurückgeben tuple. Dies ist die Redewendung für die Rückgabe mehrerer Werte. Aus demselben Grund lassen Sie die Parens mit der Swap-Sprache x, y = y, x, der Mehrfachinitialisierung x, y = 0, 1usw.; Sicher, es macht tuples unter der Haube, aber es gibt keinen Grund, dies explizit zu machen, da das tuples überhaupt nicht der Punkt ist. Das Python-Tutorial führt mehrere Aufgaben ein, lange bevor es tuples berührt .
ShadowRanger
@ShadowRanger Jede Folge von Werten, die durch ein Komma auf der rechten Seite von getrennt sind, =ist in Python ein Tupel mit oder ohne Klammern. Es gibt hier also eigentlich keine expliziten oder impliziten. a, b, c ist ebenso ein Tupel wie (a, b, c). Es gibt auch kein Tupel "unter der Haube", wenn Sie solche Werte zurückgeben, weil es nur ein einfaches Tupel ist. Das OP erwähnte bereits Tupel, so dass es tatsächlich keinen Unterschied zwischen dem, was er erwähnte, und dem, was diese Antwort zeigt, gibt. Keine
Ken4scholars
2
Dies ist buchstäblich die erste Option, die in der Frage vorgeschlagen wird
Endolith
1
@endolith Die zwei Fragen, die der Typ stellt ("Wie gebe ich mehrere Werte zurück?" und "Wie gebe ich mehrere Werte zurück?"), werden durch diese Antwort beantwortet. Der Text der Frage hat sich manchmal geändert. Und es ist eine meinungsbasierte Frage.
Joseph Hansen
74

Ich stimme für das Wörterbuch.

Ich finde, wenn ich eine Funktion erstelle, die mehr als 2-3 Variablen zurückgibt, falte ich sie in einem Wörterbuch zusammen. Ansonsten neige ich dazu, die Reihenfolge und den Inhalt meiner Rücksendung zu vergessen.

Durch die Einführung einer speziellen Struktur wird es außerdem schwieriger, Ihrem Code zu folgen. (Jemand anderes muss den Code durchsuchen, um herauszufinden, was er ist.)

Wenn Sie Bedenken hinsichtlich der Typensuche haben, verwenden Sie beschreibende Wörterbuchschlüssel, z. B. "Liste der x-Werte".

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }
Mönch
quelle
5
Nach vielen Jahren der Programmierung tendiere ich dazu, was auch immer die Struktur der Daten und Funktionen erfordert. Funktion zuerst können Sie jederzeit nach Bedarf umgestalten.
Mönch
Wie würden wir die Werte im Wörterbuch erhalten, ohne die Funktion mehrmals aufzurufen? Zum Beispiel, wenn ich y1 und y3 in einer anderen Funktion verwenden möchte?
Matt
3
Ordnen Sie die Ergebnisse einer separaten Variablen zu. result = g(x); other_function(result)
Mönch
1
@monkut ja. Auf diese Weise können Sie das Ergebnis auch an mehrere Funktionen übergeben, die unterschiedliche Argumente vom Ergebnis übernehmen, ohne jedes Mal bestimmte Teile des Ergebnisses spezifisch referenzieren zu müssen.
Gnudiff
38

Eine andere Option wäre die Verwendung von Generatoren:

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4


>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

Obwohl IMHO-Tupel normalerweise am besten sind, außer in Fällen, in denen die zurückgegebenen Werte Kandidaten für die Kapselung in einer Klasse sind.

rlms
quelle
1
Dies scheint die sauberste Lösung zu sein und hat eine saubere Syntax. Gibt es irgendwelche Nachteile? Wenn Sie nicht alle Renditen verwenden, warten dann nicht ausgegebene Renditen darauf, Sie zu verletzen?
Jiminion
24
Dies mag "sauber" sein, scheint aber überhaupt nicht intuitiv zu sein. Wie würde jemand, der dieses Muster noch nie zuvor gesehen hat, wissen, dass das automatische Auspacken von Tupeln jedes auslösen würde yield?
Coredumperror
1
@CoreDumpError, Generatoren sind genau das ... Generatoren. Es gibt keinen externen Unterschied zwischen def f(x): …; yield b; yield a; yield rvs. (g for g in [b, a, r])und beide werden leicht in Listen oder Tupel konvertiert und unterstützen als solche das Entpacken von Tupeln. Die Tupelgeneratorform folgt einem funktionalen Ansatz, während die Funktionsform unbedingt erforderlich ist und eine Flusssteuerung und Variablenzuweisung ermöglicht.
Sleblanc
30

Ich bevorzuge es, Tupel zu verwenden, wenn sich ein Tupel "natürlich" anfühlt. Koordinaten sind ein typisches Beispiel, bei dem die einzelnen Objekte für sich allein stehen können, z. B. bei nur einachsigen Skalierungsberechnungen, und die Reihenfolge ist wichtig. Hinweis: Wenn ich die Elemente sortieren oder mischen kann, ohne die Bedeutung der Gruppe zu beeinträchtigen, sollte ich wahrscheinlich kein Tupel verwenden.

Ich verwende Wörterbücher nur dann als Rückgabewert, wenn die gruppierten Objekte nicht immer gleich sind. Denken Sie an optionale E-Mail-Header.

Für den Rest der Fälle, in denen die gruppierten Objekte innerhalb der Gruppe eine inhärente Bedeutung haben oder ein vollwertiges Objekt mit eigenen Methoden benötigt wird, verwende ich eine Klasse.

tzot
quelle
29

Ich bevorzuge:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

Es scheint, dass alles andere nur zusätzlicher Code ist, um dasselbe zu tun.

UnkwnTech
quelle
22
Tupel sind einfacher zu entpacken: y0, y1, y2 = g () mit einem Diktat, das Sie ausführen müssen: result = g () y0, y1, y2 = result.get ('y0'), result.get ('y1') ), result.get ('y2'), was ein bisschen hässlich ist. Jede Lösung hat ihre Vor- und Nachteile.
Oli
27
>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3
WebQube
quelle
@edouard Nein, tut es nicht, es gibt ein Tupel zurück, keine Liste.
Simon Hibbs
1
Destrukturierung ist meiner Meinung nach das Argument für die Rückgabe von Listen
Semiomant
21

Im Allgemeinen ist die "spezialisierte Struktur" tatsächlich ein vernünftiger aktueller Zustand eines Objekts mit eigenen Methoden.

class Some3SpaceThing(object):
  def __init__(self,x):
    self.g(x)
  def g(self,x):
    self.y0 = x + 1
    self.y1 = x * 3
    self.y2 = y0 ** y3

r = Some3SpaceThing( x )
r.y0
r.y1
r.y2

Ich finde gerne Namen für anonyme Strukturen, wo dies möglich ist. Bedeutungsvolle Namen machen die Dinge klarer.

S.Lott
quelle
20

Pythons Tupel, Diktate und Objekte bieten dem Programmierer einen reibungslosen Kompromiss zwischen Formalität und Komfort für kleine Datenstrukturen ("Dinge"). Für mich hängt die Wahl, wie eine Sache dargestellt werden soll, hauptsächlich davon ab, wie ich die Struktur verwenden werde. In C ++ ist es eine übliche Konvention, structnur für Datenelemente und classfür Objekte mit Methoden zu verwenden, obwohl Sie Methoden legal auf a setzen können struct. Meine Gewohnheit ist in Python ähnlich, mit dictund tupleanstelle vonstruct .

Für Koordinatensätze verwende ich tupleeher einen als einen Punkt classoder einen dict(und beachte, dass Sie einen tupleals Wörterbuchschlüssel verwenden können, dictum großartige, spärliche mehrdimensionale Arrays zu erstellen).

Wenn ich eine Liste von Dingen durchlaufen möchte, entpacke ich lieber tuples in der Iteration:

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

... da die Objektversion unübersichtlicher zu lesen ist:

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

... geschweige denn die dict.

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

Wenn das Ding weit verbreitet ist und Sie an mehreren Stellen im Code ähnliche, nicht triviale Operationen ausführen, lohnt es sich normalerweise, es zu einem Klassenobjekt mit geeigneten Methoden zu machen.

Wenn ich Daten mit Nicht-Python-Systemkomponenten austauschen möchte, behalte ich sie meistens in einem, dictda dies für die JSON-Serialisierung am besten geeignet ist.

Russell Borogove
quelle
19

+1 auf S.Lotts Vorschlag einer benannten Containerklasse.

Ab Python 2.6 bietet ein benanntes Tupel eine nützliche Möglichkeit, diese Containerklassen einfach zu erstellen. Die Ergebnisse sind "leichtgewichtig und erfordern nicht mehr Speicher als normale Tupel".

John Fouhy
quelle
4

In Sprachen wie Python würde ich normalerweise ein Wörterbuch verwenden, da es weniger Aufwand erfordert als das Erstellen einer neuen Klasse.

Wenn ich jedoch ständig denselben Satz von Variablen zurückgebe, handelt es sich wahrscheinlich um eine neue Klasse, die ich herausrechnen werde.

Fluffels
quelle
4

Ich würde ein Diktat verwenden, um Werte von einer Funktion zu übergeben und zurückzugeben:

Verwenden Sie die im Formular definierte variable Form .

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}


def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

Dies ist der effizienteste Weg für mich und für die Verarbeitungseinheit.

Sie müssen nur einen Zeiger übergeben und nur einen Zeiger zurückgeben.

Sie müssen die Argumente von Funktionen (Tausende von ihnen) nicht ändern, wenn Sie Änderungen an Ihrem Code vornehmen.

Elis Byberi
quelle
Diktate sind veränderlich. Wenn Sie ein Diktat an eine Funktion übergeben und diese Funktion das Diktat bearbeitet, werden Änderungen außerhalb des Bereichs dieser Funktion wiedergegeben. Wenn die Funktion am Ende das Diktat zurückgibt, bedeutet dies möglicherweise, dass die Funktion keine Nebenwirkungen hat. Daher sollte der Wert nicht zurückgegeben werden, um zu verdeutlichen, dass testder Wert direkt geändert wird. Vergleichen Sie dies mit dict.update, das keinen Wert zurückgibt.
Sleblanc
@sleblanc "Wenn die Funktion am Ende das Diktat zurückgibt, bedeutet dies möglicherweise, dass die Funktion keine Nebenwirkungen hat." Dies bedeutet nicht, dass das Diktat, wie Sie sagten, veränderlich ist. Die Rückgabe beeinträchtigt formjedoch weder die Lesbarkeit noch die Leistung. In Fällen, in denen Sie möglicherweise eine Neuformatierung durchführen müssen form, stellt die Rückgabe des Formulars sicher, dass das letzte formzurückgegeben wird, da Sie die Formularänderungen nirgendwo verfolgen können.
Elis Byberi
3

"Best" ist eine teilweise subjektive Entscheidung. Verwenden Sie Tupel für kleine Rückgabesätze im allgemeinen Fall, wenn eine unveränderliche Menge akzeptabel ist. Ein Tupel ist einer Liste immer vorzuziehen, wenn keine Veränderlichkeit erforderlich ist.

Für komplexere Rückgabewerte oder für den Fall, dass Formalität wertvoll ist (dh Code mit hohem Wert), ist ein benanntes Tupel besser. Für den komplexesten Fall ist ein Objekt normalerweise am besten. Es ist jedoch wirklich die Situation, die zählt. Wenn es sinnvoll ist, ein Objekt zurückzugeben, weil Sie dies natürlich am Ende der Funktion haben (z. B. Factory-Muster), geben Sie das Objekt zurück.

Wie der Weise sagte:

Vorzeitige Optimierung ist die Wurzel allen Übels (oder zumindest des größten Teils davon) in der Programmierung.

joel3000
quelle
1
Donald Knuth sagte es (1974).
Peter Mortensen