2013-05-10 4 views
5

Ich habe eine Funktion, und wenn es aufgerufen wird, möchte ich wissen, was der Rückgabewert zugewiesen wird - insbesondere wenn es als ein entpackt wird Tupel. Also:Finden Sie heraus, in wie viele Werte ein Rückgabewert entpackt wird

a = func()   # n = 1 

gegen

a, b, c = func() # n = 3 

Ich möchte den Wert von n in func verwenden. Es muss etwas Magie mit inspect oder _getframe sein, die mich das tun lassen. Irgendwelche Ideen?


Haftungsausschluss (weil dies scheint notwendig heutzutage zu sein): Ich weiß, das ist funky und schlechte Praxis und soll nicht in Produktionscode verwendet werden. Es sieht tatsächlich so aus, als würde ich etwas in Perl erwarten. Ich bin nicht auf der Suche nach einem anderen Weg, mein vermeintlich "aktuelles" Problem zu lösen, aber ich bin neugierig, wie ich erreichen kann, wonach ich gefragt habe. Eine kühle Nutzung dieser Trick wäre:

ONE, TWO, THREE = count() 
ONE, TWO, THREE, FOUR = count() 

mit

def count(): 
    n = get_return_count() 
    if not n: 
     return 
    return range(n) 
+0

Sie können die Länge des zurückgegebenen Werts überprüfen und Zuordnungen basierend auf dieser Länge durchführen. –

+0

Was ist der Zweck? Sie können von der Funktion selbst wissen, wie viele Elemente zurückgegeben werden, oder Sie können einfach 'len (foo())' im Aufrufer verwenden. Ich habe das Gefühl, dass dies eine Lösung ist, die nach einem Problem sucht. –

+0

@AshwiniChaudhary: Nein, ich bin immer noch in der Funktion 'func' und habe noch nichts zurückgegeben, also kann ich' len' nicht aufrufen. Wenn der Aufrufer 'a, b = func()' tut, gebe ich 2 Elemente zurück. Wenn der Aufrufer 'a, b, c = func()' tut, gebe ich 3 zurück. Ich möchte in func wissen, was der Aufrufer mit dem Rückgabewert machen wird. – jdm

Antwort

4

Es gibt wenig Magie, wie Python tut dies. Wenn Sie auf der linken Seite mehr als einen Zielnamen verwenden, muss der rechte Ausdruck eine Sequenz mit übereinstimmender Länge zurückgeben.

Funktionen, die mehr als einen Wert zurückgeben, geben nur einen Tupel zurück. Das ist eine Standard-Python-Struktur, eine Sequenz bestimmter Länge. Sie können diese Länge messen:

retval = func() 

print len(retval) 

Zuordnung auspacken bei kompilieren Zeit bestimmt wird, können Sie nicht dynamisch mehr Argumente auf der linken Seite fügen Sie die Funktion passen Sie anrufen.

Python 3 können Sie eine Splat-Syntax verwenden, einen Platzhalter, für den Rest einer entpackten Zuordnung erfassen:

a, b, *c = func() 

c wird nun eine Liste mit den verbliebenen Werte über den ersten 2 sein:

>>> def func(*a): return a 
... 
>>> a, b, *c = func(1, 2) 
>>> a, b, c 
(1, 2, []) 
>>> a, b, *c = func(1, 2, 3) 
>>> a, b, c 
(1, 2, [3]) 
>>> a, b, *c = func(1) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: need more than 1 value to unpack 
+0

Der Wildcard-Trick ist nett, das muss ich mir merken. – jdm

9

von http://code.activestate.com/recipes/284742-finding-out-the-number-of-values-the-caller-is-exp/ Angepasst:

import inspect 
import dis 

def expecting(offset=0): 
    """Return how many values the caller is expecting""" 
    f = inspect.currentframe().f_back.f_back 
    i = f.f_lasti + offset 
    bytecode = f.f_code.co_code 
    instruction = ord(bytecode[i]) 
    if instruction == dis.opmap['UNPACK_SEQUENCE']: 
     return ord(bytecode[i + 1]) 
    elif instruction == dis.opmap['POP_TOP']: 
     return 0 
    else: 
     return 1 

def count(): 
    # offset = 3 bytecodes from the call op to the unpack op 
    return range(expecting(offset=3)) 

Oder als ob ject, das erkennen kann, wenn es entpackt wird:

class count(object): 
    def __iter__(self): 
     # offset = 0 because we are at the unpack op 
     return iter(range(expecting(offset=0))) 
+0

+1: Das ist ein besserer Hack als meins, weil es die richtige Aufgabe bekommt. – DSM

Verwandte Themen