2017-04-19 4 views
5

Gibt es eine Möglichkeit, innerhalb einer Funktion zu wissen, ob die Funktion von selbst aufgerufen oder einer Variablen mit = zugewiesen wurde?Kann eine Funktion wissen, wie sie aufgerufen wurde?

Ich möchte so etwas wie dies tun:

def func(): 
    if 'assigned with equal': 
     return 5 
    else: 
     print 'not assigned' 

, die diese Ausgänge geben würde:

func() 
-> 'not assigned' 
a = func() 
a 
-> 5 
+10

Es ist nicht möglich. –

+1

Ich würde das nicht versuchen. Haben Sie 1 Version, die zurückgibt, dann drucken Sie den Rückgabewert bei Bedarf an der Aufrufsite. Im Allgemeinen sollten Sie versuchen, dass Funktionen konsistent den gleichen Typ zurückgeben oder zumindest konsistent entweder einen verwendbaren Wert zurückgeben oder nicht. – Carcigenicate

+1

im Falle der Klasse können Sie es tun, indem Sie eine Klassenvariable zuweisen. – Thameem

Antwort

2

Ja, es gibt eine Möglichkeit, dies zu tun, obwohl es richtig hinzubekommen schwierig sein wird . Sie können das Modul inspect verwenden, um auf den Aufruf-Stack zuzugreifen. So können Sie sehen, wie der Code aussieht, der die Funktion genannt wird.

Der Stapel sieht ungefähr so ​​aus:

[(<frame object at 0x107de1d38>, 'path/to/function/file.py', 6, 'func', ['\tstack = inspect.stack()\n'], 0), (<frame object at 0x107d34050>, 'path/to/calling/file.py', 17, '<module>', ['func()\n'], 0)] 

Hinweis der zweiten zum letzten Eintrag: ['func()\n']. Dies zeigt den Code, der Ihre Funktion aufruft. Auch wenn der Name der Funktion an anderer Stelle im Stack erscheint, zeigt sie immer den tatsächlichen Namen der Funktion an, egal wie sie aufgerufen wird. Sie müssen also selbst ein wenig arbeiten, um festzustellen, ob der Anruf direkt oder über eine zugewiesene Variable erfolgte.

Dies ist die einzige Möglichkeit, den Funktionsnamen zu erhalten. Python does not have a feature, um den Funktionsnamen innerhalb der Funktion selbst abzurufen.

Um klarzustellen, dass dies schwieriger als nur if func_name in stack sein wird, habe ich die Funktion ein wenig konkretisiert, um ein paar Beispiele aus der realen Welt zu zeigen, wie eine Funktion heißen könnte und wie sie aussehen würde. Da die Funktion ihren eigenen Namen nicht bestimmen kann, ist sie oben in der Funktion fest codiert.

import inspect 


def func(var=None, default=''): 
    my_name = 'func' 
    stack = inspect.stack() 
    func_call = stack[-1][4][0] 
    print func_call.rstrip() # `func_call` contains a trailing newline 

    # logic to determine if the name matches 
    # ... 
    # ... 


x = func 
func() 
return_value = x(var=1) 
print func() 
if x(): 
    pass 

Diese Drucke:

func() 
return_value = x(var=1) 
print func() 
None # This prints from the call, because `func()` doesn't return anything 
if x(): 
+0

Wie kann dies die akzeptierte Antwort sein, wenn sie die Frage nicht beantwortet? Um den Namen zu erhalten, wurde die Funktion aufgerufen, und die Quellzeile reicht definitiv nicht aus, um zu bestimmen, ob das Ergebnis einem Namen zugewiesen wird oder nicht. – BlackJack

+0

@BlackJack Es ist genug Informationen, Sie müssen nur Ihre eigene Logik dafür schreiben. Der Anruf ist da, der Name ist da. Wie Sie feststellen, ob der Name in dem Anruf ist, liegt an Ihnen. –

+0

@BlackJack Ich habe nicht gefordert, dass die Funktion ausfallsicher ist, diese Antwort gab die Elemente, um genau das Ergebnis zu erzeugen, das ich in meiner Frage beschrieben habe. Die Tatsache, dass die Funktion in anderen Fällen nicht verwendet werden kann, ist für meine Frage irrelevant, aber es lohnt sich, darauf hingewiesen zu werden. – Seb

0

Hier ist ein Beispiel, das ich laufen auf der Grundlage der akzeptierten Antwort schrieb. Wir können der Funktion keinen neuen Namen zuweisen, aber was ich machen möchte

import inspect 

# generator function to get all the strings in an iterable object 
def descend_strings(obj): 
    if hasattr(obj,'__iter__'): 
     if type(obj)==dict: 
      for key in obj: 
       for result in descend_strings(obj[key]): 
        yield result 
     else: 
      for item in obj: 
       for result in descend_strings(item): 
        yield result 
    if type(obj)==str: 
     yield obj 

def func(): 
    stack = inspect.stack() 

    joined_flat_stack_str = ''.join(list(descend_strings(stack))) 

    if ('= func()' in joined_flat_stack_str) or ('print func()' in joined_flat_stack_str): 
     return 5 
    else: 
     print 'not assigned' 


func()  # 'not assigned' 
a = func() 
print a  # 5 
print func() # 5 

x = func 
x()   # 'not assigned' 
a = x()  # 'not assigned' 
print a  # None 
+0

Es ist ziemlich begrenzt. 'a, b = spam(), func()' oder 'x = spam (func())' sind Fälle, in denen der Rückgabewert zugewiesen/verwendet, aber nicht von Ihrer Inspektion erkannt wird. Das 'func()' hat eine wirklich seltsame und überraschende API. – BlackJack

Verwandte Themen