Modifier le comportement des fonctions de l'exécutable peut être fait en utilisant un décorateur:
#!/usr/bin/env python
from module1 import foo
from module2 import bar
def trace(f):
def tracewrapper(*arg, **kw):
arg_str=','.join(['%r'%a for a in arg]+['%s=%s'%(key,kw[key]) for key in kw])
print "%s(%s)" % (f.__name__, arg_str)
return f(*arg, **kw)
return tracewrapper
verbose_functions=[foo,bar] # add whatever functions you want logged here
for func in verbose_functions:
globals()[func.func_name]=trace(func)
Puisque vous ne modifiez la définition des fonctions dans l'espace de noms de l'exécutable, les fonctions des modules restent intacts. Lorsque la fonction d'un module appelle la fonction d'un autre module, elle n'est pas décomposée par trace et aucune instruction n'est générée.
Si vous souhaitez connecter des appels de fonction que quand ils viennent directement de main(), alors vous pouvez utiliser un décorateur de trace comme ceci:
import traceback
def trace(f,filename,funcname):
def tracewrapper(*arg, **kw):
stacks=traceback.extract_stack()
(s_filename,s_lineno,s_funcname,s_text)=stacks[-2]
# Alternatively, you can search the entire call stack
# for (s_filename,s_lineno,s_funcname,s_text) in stacks:
if s_filename.endswith(filename) and s_funcname==funcname:
arg_str=','.join(['%r'%a for a in arg]+
['%s=%s'%(key,kw[key]) for key in kw])
print "%s(%s)" % (f.__name__, arg_str)
return f(*arg, **kw)
return tracewrapper
verbose_functions=[foo,bar] # add whatever functions you want logged here
for func in verbose_functions:
# You can pass the module's filename and the function name here
globals()[func.func_name]=trace(func,'test.py','main')
Notez que la trace ci-dessus
def baz():
foo(3,4)
def main():
foo(1,2,'Hi')
bar(x=3)
baz()
se connecter les foo(1,2,'Hi')
et bar(x=3)
appels, mais pas foo(3,4)
depuis cet appel ne vient pas directement de la main. Cependant, il vient indirectement de principal, puisque les appels principaux baz
. Si vous souhaitez connecter l'appel foo(3,4)
, alors vous voulez boucle à travers l'ensemble de la pile:
import traceback
def trace(f,filename,funcname):
def tracewrapper(*arg, **kw):
stacks=traceback.extract_stack()
for (s_filename,s_lineno,s_funcname,s_text) in stacks:
if s_filename.endswith(filename) and s_funcname==funcname:
arg_str=','.join(['%r'%a for a in arg]+
['%s=%s'%(key,kw[key]) for key in kw])
print "%s(%s)" % (f.__name__, arg_str)
return f(*arg, **kw)
return tracewrapper
« Accepter » programmation orientée ;-) – jldupont