Załóżmy, że myapp/foo.py
zawiera:
def info(msg):
caller_name = ????
print '[%s] %s' % (caller_name, msg)
I myapp/bar.py
zawiera:
import foo
foo.info('Hello') # => [myapp.bar] Hello
W tym przypadku chcę caller_name
ustawić __name__
atrybut modułu funkcji wywołujących (czyli „myapp.foo”). Jak można to zrobić?
python
stack-trace
introspection
Sridhar Ratnakumar
źródło
źródło
caller_name
nie może być__main__
Odpowiedzi:
Sprawdź moduł inspekcji:
inspect.stack()
zwróci informacje o stosie.Wewnątrz funkcji
inspect.stack()[1]
zwraca stos dzwoniącego. Stamtąd możesz uzyskać więcej informacji o nazwie funkcji dzwoniącego, module itp.Zobacz dokumentację, aby uzyskać szczegółowe informacje:
http://docs.python.org/library/inspect.html
Ponadto Doug Hellmann ma fajny opis modułu inspekcji w swojej serii PyMOTW:
http://pymotw.com/2/inspect/index.html#module-inspect
EDYCJA: Oto kod, który robi to, co chcesz, myślę:
import inspect def info(msg): frm = inspect.stack()[1] mod = inspect.getmodule(frm[0]) print '[%s] %s' % (mod.__name__, msg)
źródło
__name__
atrybut tego modułu za pomocąinspect
modułu? Na przykład, jak mogę wrócićmyapp.foo
(niemyapp/foo.py
) w powyższym przykładzie? Próbowałem już skorzystać z modułu inspekcji przed wysłaniem wiadomości do SO.inspect.stack()[2]
dla prawdziwego dzwoniącego.W obliczu podobnego problemu stwierdziłem, że sys._current_frames () z modułu sys zawiera interesujące informacje, które mogą Ci pomóc, bez konieczności importowania inspekcji, przynajmniej w określonych przypadkach użycia.
>>> sys._current_frames() {4052: <frame object at 0x03200C98>}
Następnie możesz „przesunąć się w górę” za pomocą f_back:
>>> f = sys._current_frames().values()[0] >>> # for python3: f = list(sys._current_frames().values())[0] >>> print f.f_back.f_globals['__file__'] '/base/data/home/apps/apricot/1.6456165165151/caller.py' >>> print f.f_back.f_globals['__name__'] '__main__'
Jako nazwę pliku możesz również użyć f.f_back.f_code.co_filename, zgodnie z sugestią Marka Roddy'ego powyżej. Nie jestem pewien ograniczeń i zastrzeżeń tej metody (najprawdopodobniej wiele wątków będzie problemem), ale zamierzam ją zastosować w moim przypadku.
źródło
sys._getframe(1)
, zamiast dzwonićsys._current_frames()
(przy okazji zwraca mapowanie ramki dla każdego wątku).inspect.currentframe()
zamiastsys._current_frames().values()[0]
.Nie polecam tego robić, ale możesz osiągnąć swój cel następującą metodą:
def caller_name(): frame=inspect.currentframe() frame=frame.f_back.f_back code=frame.f_code return code.co_filename
Następnie zaktualizuj istniejącą metodę w następujący sposób:
def info(msg): caller = caller_name() print '[%s] %s' % (caller, msg)
źródło
__name__