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?
y3
, der den gleichen Job erledigt .
y3
Ihren hervorragenden Beispielen verwenden Sie eine Variable , aber wenn y3 nicht als global deklariert ist, würde diesNameError: global name 'y3' is not defined
möglicherweise nur eine Verwendung ergeben3
?