Anzahl der Rückgabewerte einer Funktion ermitteln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Nergal
User
Beiträge: 72
Registriert: Montag 6. Oktober 2008, 14:02

Dienstag 24. März 2009, 11:52

Hi,

ich suche eine Möglichkeit, an die Anzahl der Rückgabewerte einer Funktion zu kommen.
Ein Beispiel:

Code: Alles auswählen

def DoSomething():
...
return Var1, Var2
DoSomething hat zwei Rückgabewerte und genau an diese Information will ich kommen, ohne die Funktion auszuführen. Schön wäre auch, wenn man an die Typen der Rückgabewerte kommen könnte.
Jemand eine Idee?


Gruß
Nergal
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Dienstag 24. März 2009, 12:02

Geht beides nicht.

Obwohl...

Code: Alles auswählen

>>> def a(): return 1, 2, 3
>>> import dis
>>> dis.dis(a)
  1           0 LOAD_CONST               4 ((1, 2, 3))
              3 RETURN_VALUE
Untersuche den Bytecode der Funktion, suche alle RETURN_VALUE-Befehle und schaue, was da vorher geladen wird. Es ist entweder eine Konstante wie in meinem Fall oder Ausdruck, der mit BUILD_TUPLE endet. In beiden Fällen kannst du die Größe anlesen. Im Falle einer Konstante kannst du sogar die Klassen ermitteln.

Stefan
Nergal
User
Beiträge: 72
Registriert: Montag 6. Oktober 2008, 14:02

Dienstag 24. März 2009, 12:06

Danke für den Tip. Sieht erstmal gut aus und ist das, was ich gesucht habe.

Gibt es eine Möglichkeit, den Output direkt in eine Variable zu packen um ihn zu parsen? Die Funktion gibt mir die Information nur auf der Konsole aus und ´´Output = dis.dis(DoSomething)´´ geht nicht.

Gruß
Nergal
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Dienstag 24. März 2009, 12:47

Funktionen haben so gesehen nur einen Rückgabewert, nicht mehrere. Das kann jetzt eben ein Tupel sein, ist dann aber immer noch nur ein Rückgabewert.

Und ganz so trivial ist es dann doch nicht, den Bytecode zu untersuchen, denn vor dem `RETURN_VALUE` kann jeder beliebige Ausdruck stehen.

Beispiele:

Code: Alles auswählen

def spam(condition):
    return (1, 2) if condition else (1,) + global_function()
oder auch etwas Absurdes wie

Code: Alles auswählen

def spam():
    try:
        return (1,2)
    finally:
        return (3, 4)
Und von C-Funktionen lässt sich mit [mod]dis[/mod] auch nicht der Rückgabewert voraussagen.

Ich lasse mich da ja gerne korrigieren, aber ich wage zu behaupten, dass man nicht gerade aus dem Stegreif den Rückgabewert aus der dis-Ausgabe parst. Also stellt sich mir die Frage: wofür eigentlich?

Edit: "nicht" eingefügt -.-
Zuletzt geändert von Trundle am Mittwoch 25. März 2009, 11:03, insgesamt 1-mal geändert.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Nergal
User
Beiträge: 72
Registriert: Montag 6. Oktober 2008, 14:02

Dienstag 24. März 2009, 13:06

Um den Sinn des Ganzen ausführlich zu erklären, müßte ich an dieser Stelle zu weit ausholen.

Es wäre einfach angenehm, wenn ich eine Funktion insofern analysieren könnte, daß ich die Anzahl der Rückgabewerte weiß, ohne sie auszuführen.
Wenn das so einfach nicht geht, habe ich ja immer noch die Alternative, sie auszuführen und den Rückgabewert dann auszuwerten. Zwar nicht so schick, aber es sollte an der Stelle ausreichen.

Gruß
Nergal
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Dienstag 24. März 2009, 13:18

Das einzig sinnvolle ist wohl, nach dem return nachzuschauen, wieviele Werte es gab (mit len()):

Code: Alles auswählen

import random
def foo():
    return tuple(42 for  _ in xrange(random.randint(0, 10000000)))
# Wieviele variablen return't foo()?
bar = foo()
hth, Jörg
ps.: Dass eine Funktion überhaupt unterschiedlich viele verschiedene Variablen zurückgeben kann, klingt für mich schon verkehrt
DasIch
User
Beiträge: 2435
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dienstag 24. März 2009, 13:28

b.esser-wisser hat geschrieben:ps.: Dass eine Funktion überhaupt unterschiedlich viele verschiedene Variablen zurückgeben kann, klingt für mich schon verkehrt
Mag daran liegen dass Funktionen nicht unterschiedliche viele Variablen zurückgeben können. Funktionen können allerdings unterschiedlich große Sequenzen zurückgeben.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Dienstag 24. März 2009, 13:36

DasIch hat geschrieben:Mag daran liegen dass Funktionen nicht unterschiedliche viele Variablen zurückgeben können. Funktionen können allerdings unterschiedlich große Sequenzen zurückgeben.
Eine Sequenz ( im Sinne von Liste/Array/generator) ist aber (in Python 8) ) nur eine "Variable", nicht viele Verschiedene (Es ginge auch anders: http://thedailywtf.com/Articles/A-Mans-Array.aspx ;) ).

Und mit einer For-schleife braucht man die Länge normalerweise auch nie (explizit).

hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
DasIch
User
Beiträge: 2435
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dienstag 24. März 2009, 16:44

Habe ich nie bestritten, zumindest wenn man Variable als Referenz auf ein Objekt definiert ansonsten schon.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 24. März 2009, 18:19

Nergal hat geschrieben:Um den Sinn des Ganzen ausführlich zu erklären, müßte ich an dieser Stelle zu weit ausholen.
Das wäre vielleicht gar nicht so schlecht, denn das riecht wie BlackJack es sagen würde nach einem "Code Smell".

Ich würde eigentlich durchaus sagen, dass Python-Funktionen immer nur einen Rückgabewert haben. Ja, es gibt Decomposition aber das halte ich eher für Syntaktischen Zucker um eine Sequenz aufzubrechen als für die Möglichkeit mehrere Rückgabewerte auf einmal zu haben.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Dienstag 24. März 2009, 18:26

@Nergal: Ich schliesse mich mal Leonidas an: Python-Funktionen haben immer nur *genau einen* Rückgabewert.

Und die Frage, die Du da anscheinend beantworten möchtest, ist alles andere als eindeutig und IMHO auch mit Aufrufen der Funktion nicht beantwortbar. Denn durch *einen* Aufruf kann man ja nicht sicher sein, dass da jedes mal eine Sequenz mit der gleichen Länge zurückgegeben wird. Oder gar ein "iterable" mit der gleichen Länge.
Nergal
User
Beiträge: 72
Registriert: Montag 6. Oktober 2008, 14:02

Mittwoch 25. März 2009, 09:37

Ich habe verschiedene Pythonscripte, die alle eine Funktion mit dem gleichen Namen enthalten und von einem Python Grundgerüst ausgeführt werden können. Diese Scripte möchte ich nun gerne vor der Ausführung analysieren, da einige schon älter sind und nur einen Parameter zurückgeben.

Werde es wohl so, wie b.esser-wisser es erwähnt hat, machen:
Funktion ausführen und dann die Länge und Datentyp des Rückgabewertes prüfen.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Mittwoch 25. März 2009, 15:56

Nergal hat geschrieben:Diese Scripte möchte ich nun gerne vor der Ausführung analysieren, da einige schon älter sind und nur einen Parameter zurückgeben.
Ach, machen das die neuen nicht mehr? Wie kann man denn in einer Funktion mehrere Objekte zurückgeben? Ich dachte immer, man kann nur ein Objekt pro Funktion zurückgeben.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Mittwoch 25. März 2009, 18:26

derdon hat geschrieben:Wie kann man denn in einer Funktion mehrere Objekte zurückgeben?
Ich dachte immer, man kann nur ein Objekt pro Funktion zurückgeben.
Technisch/syntaktisch ist das auch so, aber Iterables (tuple, listen, etc) können ja automatisch entpackt werden:

Code: Alles auswählen

>>> def foo( bar, baz, *args, **kwargs):
	return baz, bar

>>> foo(0,1)
(1, 0)
>>> test = foo(0,1)
>>> print type(test), repr(test)
<type 'tuple'> (1, 0)
>>> a, b = foo( *range(100))
>>>#            ^ man kann auch selbst auspacken
>>>#              der Rest landet hier im tuple `args'
>>> a
1
>>> b
0
hth, Jörg
Antworten