Seite 1 von 1
Anzahl der Rückgabewerte einer Funktion ermitteln
Verfasst: Dienstag 24. März 2009, 11:52
von Nergal
Hi,
ich suche eine Möglichkeit, an die Anzahl der Rückgabewerte einer Funktion zu kommen.
Ein Beispiel:
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
Verfasst: Dienstag 24. März 2009, 12:02
von sma
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
Verfasst: Dienstag 24. März 2009, 12:06
von Nergal
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
Verfasst: Dienstag 24. März 2009, 12:47
von Trundle
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
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 -.-
Verfasst: Dienstag 24. März 2009, 13:06
von Nergal
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
Verfasst: Dienstag 24. März 2009, 13:18
von b.esser-wisser
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
Verfasst: Dienstag 24. März 2009, 13:28
von DasIch
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.
Verfasst: Dienstag 24. März 2009, 13:36
von b.esser-wisser
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

) 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
Verfasst: Dienstag 24. März 2009, 16:44
von DasIch
Habe ich nie bestritten, zumindest wenn man Variable als Referenz auf ein Objekt definiert ansonsten schon.
Verfasst: Dienstag 24. März 2009, 18:19
von Leonidas
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.
Verfasst: Dienstag 24. März 2009, 18:26
von BlackJack
@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.
Verfasst: Mittwoch 25. März 2009, 09:37
von Nergal
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.
Verfasst: Mittwoch 25. März 2009, 15:56
von derdon
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.
Verfasst: Mittwoch 25. März 2009, 18:26
von b.esser-wisser
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