Wie Sie mehrere Werte in Python zurückgeben?

stimmen
768

Die kanonische Möglichkeit , mehrere Werte in Sprachen zurückzugeben , die sie unterstützen , ist oft fache Vervielfachung .

Option: Mit Hilfe eines Tupels

Betrachten Sie diese triviales Beispiel:

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

Dies ist jedoch schnell wird problematisch, da die Anzahl der Werte erhöht zurückgegeben. Was passiert, wenn Sie vier oder fünf Werte zurückgeben möchten? Natürlich könnten Sie sie halten fache Vervielfachung, aber es wird leicht zu vergessen, welcher Wert ist, wo. Es ist auch ziemlich hässlich, sie zu entpacken, wo Sie sie erhalten möchten.

Option: Mit einem Wörterbuch

Der nächste logische Schritt scheint eine Art von ‚record Notation‘ zu sein einzuführen. In Python, die offensichtliche Art und Weise , dies zu tun ist durch ein dict.

Folgendes berücksichtigen:

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

(Editier- Nur klar, y0, y1 und y2 zu sein sind nur als abstrakter Bezeichner gemeint. Wie erwähnt, in der Praxis würden Sie aussagekräftige Bezeichner verwenden)

Jetzt haben wir einen Mechanismus, mit dem wir ein bestimmtes Mitglied des zurückgegebenen Objekts projizieren kann. Beispielsweise,

result['y0']

Option: Mit einer Klasse

Allerdings gibt es eine weitere Option. Wir könnten stattdessen eine spezielle Struktur zurück. Ich habe dies im Zusammenhang mit dem Python gerahmt, aber ich bin sicher, dass es auch auf andere Sprachen gilt. Tatsächlich ist dies sehr gut, wenn Sie in C arbeiteten könnte Ihre einzige Option sein. Hier geht:

class ReturnValue(object):
  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 die letzte beide vielleicht sehr ähnlich in Bezug auf Klima- Denn { y0, y1, y2 }nur seinen Eintrag in den internen Ende __dict__der ReturnValue.

Es ist ein zusätzliches Merkmal von Python zur Verfügung gestellt , obwohl für kleine Objekte, 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__Erklärung nimmt eine Folge von Instanzvariablen und Reserven nur noch genügend Platz jeweils einen Wert für jede Variable zu halten. Platz gespart , weil __dict__nicht für jede Instanz erstellt.

Option: Mit einer Liste

Ein weiterer Vorschlag, die ich hätte kommt von Bill übersehen die Eidechse:

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

Dies ist meine unbeliebtesten Methode though. Ich glaube , ich durch die Einwirkung von Haskell verdorben bin, aber die Idee von Mischtyp - Listen immer unangenehm für mich fühlte. In diesem speziellen Beispiel ist die Liste -not- Mischtyp, aber es könnte denkbar sein. Eine Liste auf diese Weise verwendet wirklich gewinnen nichts in Bezug auf die Tupel, soweit ich das beurteilen kann. Der einzige wirkliche Unterschied zwischen Listen und Tupel in Python ist , dass die Listen sind wandelbar , wheras Tupel nicht. I neigen persönlich die Konventionen von funktionaler Programmierung übertragen: Verwendung Listen für eine beliebige Anzahl von Elementen des gleichen Typs und Tupeln für eine feste Anzahl von Elementen der vorbestimmten Typen.

Frage

Nach der langen Präambel kommt die unvermeidliche Frage. Welche Methode (glauben Sie) ist am besten?

Ich habe normalerweise fand mich das Wörterbuch Weg zu gehen , weil es weniger Set-up beinhaltet Arbeit. Jedoch von einem Typ Perspektive, könnten Sie besser dran , wenn man die Klasse Route sein, da damit ihnen helfen , zu vermeiden verwirrend , was ein Wörterbuch darstellt. Auf der anderen Seite gibt es einige in der Python - Community ist , die das Gefühl implizite Schnittstellen sollten explizite Schnittstellen bevorzugt werden , bei denen die Art des Objekts zeigt wirklich nicht relevant ist, sind da Sie im Grunde auf der Konvention , die das gleiche Attribut unter Berufung immer die gleiche Bedeutung haben.

Also, wie -you- mehrere Werte in Python zurückgeben?

Veröffentlicht am 10/12/2008 um 00:55
quelle vom benutzer
In anderen Sprachen...                            


14 antworten

stimmen
17

ich bevorzuge

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

es scheint, alles andere nur zusätzliche Code ist, das Gleiche zu tun.

Beantwortet am 10/12/2008 um 01:00
quelle vom benutzer

stimmen
2

In Sprachen wie Python, würde ich in der Regel einen Wörterbuch verwenden, da es weniger Overhead beinhaltet als eine neue Klasse zu schaffen.

Allerdings, wenn ich mich ständig den gleichen Satz von Variablen zurückkehrt, dann ist das wahrscheinlich eine neue Klasse beinhaltet, die ich aus Faktor werden.

Beantwortet am 10/12/2008 um 01:02
quelle vom benutzer

stimmen
11

Im Allgemeinen ist die „spezialisierte Struktur“ eigentlich ein vernünftiger aktueller Zustand eines Objekts, mit seinen 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 mag Namen für anonyme Strukturen, wo möglich, finden. Bedeutungsvolle Namen machen Dinge klarer.

Beantwortet am 10/12/2008 um 01:15
quelle vom benutzer

stimmen
156

Für kleine Projekte finde ich es am einfachsten, mit Tupeln zu arbeiten. Wenn das zu hart wird zu verwalten (und nicht vor) ich die Dinge in logische Strukturen beginnen Gruppierung, aber ich denke, Ihre vorgeschlagene Verwendung von Wörterbüchern und Return Objekte falsch ist (oder zu einfach).

Wiederkehrende ein Wörterbuch mit den Tasten y0, y1, y2 usw. bietet keinen Vorteil gegenüber Tupel. irgendeinen Vorteil gegenüber Tupeln entweder bietet keine Return Instanz mit Eigenschaften .y0 .y1 .y2 etc zurück. Sie müssen die Benennung Dinge beginnen, wenn Sie überall bekommen wollen, und Sie können tun, dass Tupel sowieso mit:

def getImageData(filename):
  [snip]
  return size, (format, version, compression), (width,height)
size, type, dimensions = getImageData(x)

IMHO, die einzige gute Technik über Tupel ist reale Objekte mit der richtigen Methoden und Eigenschaften zurückzukehren, wie Sie bekommen re.match()oder open(file).

Beantwortet am 10/12/2008 um 01:22
quelle vom benutzer

stimmen
19

Ich ziehe es Tupel zu verwenden, wenn ein Tupel fühlt sich „natürlich“; Koordinaten ist ein typisches Beispiel, wo die einzelnen Objekte auf ihrer eigenen, zum Beispiel in einer Achse nur Skalierung Berechnungen und die Reihenfolge ist wichtig, stehen können. Hinweis: Wenn ich die Einzelteile ohne negative Auswirkungen auf die Bedeutung der Gruppe sortieren oder mischen kann, dann sollte ich wahrscheinlich kein Tupel verwenden.

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

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

Beantwortet am 10/12/2008 um 01:40
quelle vom benutzer

stimmen
49

Ich wähle für das Wörterbuch.

Ich finde, dass wenn ich eine Funktion machen, die etwas mehr als 2-3 Variablen zurückgibt Ich werde sie in einem Wörterbuch zusammenfalten. Ansonsten neige ich dazu, die Reihenfolge und den Inhalt zu vergessen, was ich zurück.

Auch eine ‚besondere‘ Struktur Einführung macht den Code schwieriger zu folgen. (Jemand anderes wird durch den Code suchen, um herauszufinden, was es ist)

Wenn Ihr besorgt über Art suchen, verwenden Sie deskriptive Dictionary-Schlüssel, zum Beispiel ‚x-Werte-Liste‘.

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }
Beantwortet am 10/12/2008 um 01:42
quelle vom benutzer

stimmen
11

+1 auf S.Lott Vorschlag einer benannten Container-Klasse.

Für Python 2.6 und höher, ein namens Tupel liefert eine nützliche Art und Weise leicht , diese Containerklassen zu schaffen, und die Ergebnisse sind „leicht und benötigen nicht mehr Speicher als normale Tupel“.

Beantwortet am 10/12/2008 um 02:51
quelle vom benutzer

stimmen
481

Benannt Tupel wurde in 2.6 zu diesem Zweck hinzugefügt. Siehe auch os.stat für ein ähnliches builtin 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
Beantwortet am 10/12/2008 um 15:36
quelle vom benutzer

stimmen
11

Pythons Tupel, dicts und Objekte bieten den Programmierer einen glatten Kompromiss zwischen Formalität und Komfort für kleine Datenstrukturen ( „Dinge“). Für mich ist die Wahl, wie eine Sache vertreten wird diktiert vor allem durch wie werde ich die Struktur verwenden. In C ++ ist es eine gemeinsame Konvention verwenden structfür Nur - Daten-Elemente und classfür Objekte mit Methoden, auch wenn Sie rechtlich Methoden auf einem setzen können struct; meine Gewohnheit ist in Python ähnlich, mit dictund tuplestatt struct.

Für Koordinatensätze, werde ich ein verwenden , tupleanstatt einen Punkt classoder ein dict(und beachten Sie, dass Sie ein verwenden können , tupleals Wörterbuch - Taste, so dicts große spärliche mehrdimensionale Arrays machen).

Wenn ich werde über eine Liste der Dinge zu iterieren, ziehe ich es auspacken tuples auf der Iteration:

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

... als die Objektversion ist unübersichtlich zu lesen:

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 finden sich ähnliche nicht-triviale Operationen auf sie an mehreren Stellen im Code zu tun, dann ist es in der Regel lohnt es ein Klassenobjekt mit geeigneten Methoden zu machen.

Schließlich, wenn ich mit nicht-Python - Systemkomponenten Austausch von Daten sein werde, werde ich meistens sie in einem halten , dictweil das zu JSON Serialisierung am besten geeignet ist.

Beantwortet am 13/08/2013 um 19:18
quelle vom benutzer

stimmen
26

Eine andere Möglichkeit wäre Generatoren mit:

>>> 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 Tupeln in der Regel am besten ist, außer in Fällen, in denen die Werte zurückgegeben werden, sind Kandidaten für die Verkapselung in einer Klasse.

Beantwortet am 23/02/2014 um 13:26
quelle vom benutzer

stimmen
20
>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3
Beantwortet am 21/01/2015 um 18:57
quelle vom benutzer

stimmen
101

Viele der Antworten vorschlagen, Sie brauchen eine Sammlung von irgendeiner Art zurück, wie ein Wörterbuch oder einer Liste. Sie könnten die zusätzliche Syntax und nur schreiben die Rückgabewerte, durch Komma getrennte wegzulassen. Hinweis: Dieses technisch ein Tupel zurück.

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

gibt:

True
False
Beantwortet am 14/04/2016 um 19:08
quelle vom benutzer

stimmen
0

Ich würde einen dict verwenden, um übergeben und Rückgabewerte aus einer Funktion:

Verwenden variabler Form , wie in definierten 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 Verarbeitungseinheit.

Sie haben nur einen Zeiger in und zurück aus nur einen Zeiger zu übergeben.

Sie müssen nicht Funktionen ändern (Tausende von ihnen) Argumente, wann immer Sie eine Änderung in Ihrem Code vornehmen.

Beantwortet am 30/10/2017 um 12:01
quelle vom benutzer

stimmen
0

„Best“ ist eine teilweise subjektive Entscheidung. Verwenden Tupeln für kleine Rücklaufmengen in dem allgemeinen Fall, in dem ein unveränderlichen akzeptabel ist. Ein Tupel ist immer besser, eine Liste, wenn Veränderlichkeit nicht erforderlich ist.

Für komplexere Rückgabewerte, oder für den Fall, dass Förmlichkeit wertvoll ist (dh hohe Wert-Code) ein benanntes Tupel ist besser. Für den komplexeste Fall ist ein Objekt in der Regel am besten. Allerdings ist es wirklich die Situation, was zählt. Wenn es sinnvoll ist, ein Objekt zurück, weil das ist, was natürlich Sie am Ende der Funktion (zB Fabrikmuster) dann das Objekt zurück.

Wie der weise Mann sagte:

Vorzeitige Optimierung ist die Wurzel aller Übel (oder zumindest die meisten davon) in der Programmierung.

Beantwortet am 29/08/2018 um 18:30
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more