如何在调用时打印函数?
问题的出现原因:
- traceit.py模块中使用了tracefunc函数来追踪函数的调用栈。
- 该模块中使用了sys.setprofile()方法将tracefunc函数设置为系统的profile函数,以便在每次函数调用时都会调用tracefunc函数。
- tracefunc函数会根据一定的条件打印出函数的信息,包括函数名、文件路径和行号等。
问题的解决方法:
- 导入traceit模块,并使用sys.setprofile()方法将tracefunc函数设置为系统的profile函数。
- 运行代码,每次函数调用时,都会打印出函数的信息。
文章整理如下:
我采用了kindall的答案并在此基础上进行了修改。我创建了以下模块:
"""traceit.py Traces the call stack. Usage: import sys import traceit sys.setprofile(traceit.traceit) """ import sys WHITE_LIST = {'trade'} # Look for these words in the file path. EXCLUSIONS = {'<'} # Ignore <listcomp>, etc. in the function name. def tracefunc(frame, event, arg): if event == "call": tracefunc.stack_level += 1 unique_id = frame.f_code.co_filename+str(frame.f_lineno) if unique_id in tracefunc.memorized: return # Part of filename MUST be in white list. if any(x in frame.f_code.co_filename for x in WHITE_LIST) \ and \ not any(x in frame.f_code.co_name for x in EXCLUSIONS): if 'self' in frame.f_locals: class_name = frame.f_locals['self'].__class__.__name__ func_name = class_name + '.' + frame.f_code.co_name else: func_name = frame.f_code.co_name func_name = '{name:->{indent}s}()'.format( indent=tracefunc.stack_level*2, name=func_name) txt = '{: <40} # {}, {}'.format( func_name, frame.f_code.co_filename, frame.f_lineno) print(txt) tracefunc.memorized.add(unique_id) elif event == "return": tracefunc.stack_level -= 1 tracefunc.memorized = set() tracefunc.stack_level = 0
示例用法:
import traceit sys.setprofile(traceit.tracefunc)
示例输出:
API.getFills() # C:\Python37-32\lib\site-packages\helpers\trade\tws3.py, 331 API._get_req_id() # C:\Python37-32\lib\site-packages\helpers\trade\tws3.py, 1053 API._wait_till_done() # C:\Python37-32\lib\site-packages\helpers\trade\tws3.py, 1026 ---API.execDetails() # C:\Python37-32\lib\site-packages\helpers\trade\tws3.py, 1187 -------Fill.__init__() # C:\Python37-32\lib\site-packages\helpers\trade\mdb.py, 256 --------Price.__init__() # C:\Python37-32\lib\site-packages\helpers\trade\mdb.py, 237 -deserialize_order_ref() # C:\Python37-32\lib\site-packages\helpers\trade\mdb.py, 644 --------------------Port() # C:\Python37-32\lib\site-packages\helpers\trade\mdb.py, 647 API.commissionReport() # C:\Python37-32\lib\site-packages\helpers\trade\tws3.py, 1118
特点:
- 忽略Python语言内部函数。
- 忽略重复的函数调用(可选)。
- 为了提高速度,使用sys.setprofile()方法而不是sys.settrace()方法。
有15行破折号打印出每个函数的信息
traceit是什么?它没有被定义,也不是一个模块
与其优化代码,不如先解决traceit未定义的问题吗?
我编辑了答案。希望现在更清楚了。
是否有这段代码的使用示例?当我尝试使用简单的foo/bar脚本时,它似乎没有任何作用。
问题:如何在函数被调用时打印函数?
原因:想要在函数被调用时打印函数的名称和返回值。
解决方法:使用跟踪函数来实现这一功能。可以通过以下代码实现:
def tracefunc(frame, event, arg, indent=[0]): if event == "call": indent[0] += 2 print("-" * indent[0] + "> call function", frame.f_code.co_name) elif event == "return": print("<" + "-" * indent[0], "exit function", frame.f_code.co_name) indent[0] -= 2 return tracefunc import sys sys.setprofile(tracefunc) main() # or whatever kicks off your script
这个跟踪函数会在函数被调用时打印出函数的名称,并在函数返回时打印出函数的退出信息。
需要注意的是,函数的代码对象通常与关联的函数具有相同的名称,但并不总是如此,因为函数可以动态创建。不幸的是,Python不会跟踪堆栈上的函数对象。如果遇到这个问题,可以从源代码中提取“真实”的函数名称,Python会跟踪文件名和行号,或者可以通过垃圾回收器找出哪个函数对象引用了代码对象。可能会有多个函数共享代码对象,但其中任何一个函数的名称都足够使用。
可以使用全局变量来跟踪嵌套级别,并使跟踪结果更加美观。
在Python 2.6及更高版本中,可以使用`sys.setprofile()`而不是`sys.settrace()`来获得更好的性能。这两个函数使用相同的跟踪函数,只是`sys.setprofile()`只在函数进入或退出时调用跟踪函数,所以函数内部的代码会以全速执行。
还可以在跟踪函数中添加代码来打印调用函数所在的文件。
如果`event`是`'c_call'`,可以使用`frame.f_code.co_name`来获取函数名称。
如果只想打印自己代码中定义的函数,而不是所有Python内部函数,可以检查`frame.f_code.co_filename`。这个属性应该是包含函数的文件的完整路径。可以检查路径中是否包含`Python`和`lib`,如果包含,则不打印任何内容。
如果想在获取方法时查看类,可以尝试使用`if "self" in frame.f_locals: print(type(frame.f_locals["self"]).__qualname__)`。
如果想在函数被调用时打印返回值,可以使用装饰器实现,但不能作为跟踪函数的一部分。