Aufrufargumente der letzten Funktion aus Traceback abrufen?
-
22-07-2019 - |
Frage
Kann ich die Parameter der zuletzt aufgerufenen Funktion im Traceback abrufen?Wie?
Ich möchte einen Fänger für Standardfehler erstellen, um lesbaren Code zu erstellen und dem Benutzer dennoch detaillierte Informationen bereitzustellen.
Im folgenden Beispiel möchte ich, dass GET_PARAMS mir ein Tupel von Parametern zurückgibt, die an os.chown bereitgestellt werden.Untersuchen der inspect
Das von Alex Martelli empfohlene Modul konnte ich nicht finden.
def catch_errors(fn):
def decorator(*args, **kwargs):
try:
return fn(*args, **kwargs)
except (IOError, OSError):
msg = sys.exc_info()[2].tb_frame.f_locals['error_message']
quit(msg.format(SEQUENCE_OF_PARAMETERS_OF_THE_LAST_FUNCTION_CALLED)\
+ '\nError #{0[0]}: {0[1]}'.format(sys.exc_info()[1].args), 1)
return decorator
@catch_errors
def do_your_job():
error_message = 'Can\'t change folder ownership \'{0}\' (uid:{1}, gid:{2})'
os.chown('/root', 1000, 1000) # note that params aren't named vars.
if __name == '__main__' and os.getenv('USERNAME') != 'root':
do_your_job()
(Dank an Jim Robert für den Dekorateur)
Lösung
Das Problem bei der Verwendung eines Dekorateur für das, was Sie erreichen wollen, ist, dass der Rahmen des Exception-Handler erhält do_your_job()
s ist, nicht os.listdir()
s, os.makedirs()
s oder os.chown()
s. So Ihre Informationen werden den Druck werden die Argumente do_your_job()
. Um das Verhalten Ich glaube, Sie erhalten möchten, würden Sie haben alle Bibliotheksfunktionen dekorieren Sie anrufen.
Andere Tipps
Denken Sie bei solchen Inspektionsaufgaben immer zuerst an das Modul inspect
in der Standardbibliothek.Hier, inspect.getargvalues gibt Ihnen die Argumentwerte für einen gegebenen Rahmen und inspect.getinnerframes liefert Ihnen die interessierenden Frames eines Traceback-Objekts.
ist ein Beispiel für eine solche Funktion und einige Probleme, die man nicht umgehen kann:
import sys
def get_params(tb):
while tb.tb_next:
tb = tb.tb_next
frame = tb.tb_frame
code = frame.f_code
argcount = code.co_argcount
if code.co_flags & 4: # *args
argcount += 1
if code.co_flags & 8: # **kwargs
argcount += 1
names = code.co_varnames[:argcount]
params = {}
for name in names:
params[name] = frame.f_locals.get(name, '<deleted>')
return params
def f(a, b=2, c=3, *d, **e):
del c
c = 4
e['g'] = 6
assert False
try:
f(1, f=5)
except:
print get_params(sys.exc_info()[2])
Die Ausgabe lautet:
{'a': 1, 'c': 4, 'b': 2, 'e': {'g': 6, 'f': 5}, 'd': ()}
habe ich nicht verwendet inspect.getinnerframes()
eine andere Art und Weise zu zeigen, benötigt Rahmen zu erhalten. Obwohl es ein wenig vereinfacht, sondern auch einige zusätzliche Arbeit tun, die nicht für Sie benötigt wird, während relativ langsam ist (inspect.getinnerframes()
liest Quelldatei für jedes Modul in Traceback, das für einen Debug-Aufruf ist nicht wichtig, aber könnte ein Problem in anderen Fällen sein ).