2012-02-08 13 views

Odpowiedz

7

Zobacz https://stackoverflow.com/a/4249347/224295, http://code.activestate.com/recipes/577283-decorator-to-expose-local-variables-of-a-function-/

przykład robocza:

import sys 

class persistent_locals(object): 
    def __init__(self, func): 
     self._locals = {} 
     self.func = func 

    def __call__(self, *args, **kwargs): 
     def tracer(frame, event, arg): 
      if event=='return': 
       self._locals = frame.f_locals.copy() 

     # tracer is activated on next call, return or exception 
     sys.setprofile(tracer) 
     try: 
      # trace the function call 
      res = self.func(*args, **kwargs) 
     finally: 
      # disable tracer and replace with old one 
      sys.setprofile(None) 
     return res 

    def clear_locals(self): 
     self._locals = {} 

    @property 
    def locals(self): 
     return self._locals 

@persistent_locals 
def func(): 
    local1 = 1 
    local2 = 2 

func() 
print func.locals 
+0

to działa. Zgadzam się, że jest to zły pomysł, ale byłem zainteresowany, czy to możliwe. – Harel

+0

Świetna sztuczka. Robię debugger, który musi podstępnie chwytać elementy wewnętrzne z dekorowanej funkcji i dlatego jest to przydatne. Należy zauważyć, że tracer() jest nazywany nie tylko powrotem funkcji zdobionej, ale także zwrotem wszystkich funkcji wywoływanych z tej funkcji. Ponieważ dekorowana funkcja zawsze ma ostatni powrót, (i dlatego ustawia _locals na koniec) nie ma to znaczenia w tym przypadku. – Peter

-2

Zamiast błahy wokół z wewnętrznych przez funkcję (która złamie jeśli funkcja urządzony jest native), napisać własne opakowania, tak:

def myDecorator(f): 
    def wrapper(*args, **kwargs): 
    print('Arguments to this function %r/%r' % (args, kwargs)) 
    return f(*args, **kwargs) 
    return wrapper 
3

<edit> Właśnie uświadomiłem sobie misread pytanie i że nie próbujesz uzyskać atrybutów funkcji, ale wartości zmiennych lokalnych z funkcji. To, co chcesz zrobić, nie jest możliwe, ponieważ te zmienne lokalne nie są tworzone, dopóki funkcja nie zostanie uruchomiona, a zakres lokalny dla tej funkcji zostanie usunięty, gdy tylko funkcja zwróci lub zgłosi wyjątek.

Pozostawiam moją oryginalną odpowiedź, ponieważ możesz potencjalnie przepisać swoją funkcję, aby używać atrybutów zamiast zmiennych lokalnych i nadal używać tego dekoratora, aby skutecznie robić to, co chcesz.

Przydałoby się opublikować to, co aktualnie próbowano, i niektóre przykładowe wywołania z oczekiwanym wynikiem, jeśli działało poprawnie. </edit>

Kiedy potrzebujesz funkcji z atrybutów, to generalnie dobry pomysł, aby użyć wpłacone klasę zamiast normalnej definicji funkcji.

Oto przykład dekoratora gdzie owinięcie jest wywoływalnym klasy, który pozwala dekorator, aby uzyskać dostęp do zmiennych łatwo, ponieważ są one zmienne instancji klasy otoki:

def deco(func): 
    class Wrapper(object): 
     def __init__(self): 
      self.foo = None 
     def __call__(self, *args): 
      print 'old foo:', self.foo 
      result = func(*args) 
      print 'new foo:', self.foo 
      return result 
    return Wrapper() 

@deco 
def my_func(new_foo): 
    my_func.foo = new_foo 

co skutkuje my_func zachowania się tak:

>>> my_func('test') 
old foo: None 
new foo: test 
>>> my_func.foo 
'test' 
>>> my_func(42) 
old foo: test 
new foo: 42 
>>> my_func.foo 
42 
-1

nie, to nie jest możliwe, aby uzyskać dostęp do zmiennych wewnątrz funkcji zapakowane, ponieważ (jak FJ wskazał w jego edycji) one nie istnieją w chwili dekorator jest w zasięgu.

5

To, o co prosisz, nie ma większego sensu.

Zmienne lokalne funkcji nie mają wartości przez cały czas. Rozważyć tę funkcję:

def foo(x): 
    y = x + 27 
    return y 

Jaka jest wartość foo „s zmiennej lokalnej y? Nie możesz odpowiedzieć, pytanie nie ma nawet sensu, dopóki nie zadzwonisz pod numer foo (a nawet wtedy, dopóki nie zostanie wykonana linia y = x + 27).

I nawet to nie tylko, że y może nie mieć wartość w tej chwili, nie może być dowolną liczbę z „w locie” egzekucji foo. Mogą istnieć wątki wykonujące foo lub foo mogą być rekursywne (prawdopodobnie pośrednio), więc istnieje więcej niż jedno wywołanie w toku, nawet w jednym stosie wywołań. Lub foo może być generatorem, więc może być wiele wykonań w locie foo nawet bez rekursji (tj.nie wszystkie są dostępne z jakiegoś zewnętrznego zakresu foo). Który z nich uzyskałby wartość: y?

Wartość y w foo po prostu nie jest dobrze zdefiniowaną koncepcją, chyba że mówisz o zakresie w zakresie foo.


Biorąc pod uwagę elastyczność Pythona, jestem całkiem pewny, że jest to możliwe do zrobienia stosu ramki introspekcji i znaleźć ramkę stosu dla foo gdy istnieje jedna obecnie mieszka i wyciągnij wartości swoich zmiennych lokalnych w tym czasie. Byłoby to dość trudne (jeśli nie niemożliwe) w związku z dekoratorem, ponieważ (chyba że foo jest generatorem) dekorator może tylko dodać kod opakowania "dookoła" foo, co oznacza, że ​​kod kontrolowany przez dekorator działa przed i po foo , więc kontrolujesz tylko wtedy, gdy ramka stosu foo nie istnieje.

Nie zamierzam podać konkretnych wskazówek, jak to zrobić, ponieważ nie wiem, jak to zrobić. Wygląda na to, że prawie na pewno jest to zły pomysł, chyba że piszesz debugger.

Powiązane problemy