代码覆盖率原理分析:sys.settrace流程分析

sys.settrace分析环境
本文环境python3.5.2
sys.settrace函数执行

首先我们继续查看示例代码如下:

import sys


def trace(frame, event, arg_unused):
    print(frame.f_lineno, event, arg_unused)
    return trace


sys.settrace(trace)

with open('test_file.py', "rb") as f:
    source = f.read()

code = compile(source, 'test_file.py', 'exec')
exec(code)

继续使用上文分析过的脚本test_file.py文件,test_file.py文件如下:

import sys

import os


def test_a():
    a = 1


def test_b():
    b = 2


def run():
    if 1:
        r = 1
    else:
        r = 2
    test_a()
    ret = r


run()

此时运行脚本输出的内容如下:

1 call None
1 line None
3 line None
6 line None
10 line None
14 line None
23 line None
14 call None
16 line None
19 line None
6 call None
7 line None
7 return None
20 line None
20 return None
23 return None

此时,我们继续修改示例代码,将trace函数中注释掉return trace这一行,此时继续运行,输出结果如下:

1 call None
14 call None
6 call None

此时的输出结果如上所述,为什么此时两次运行的结果会出现差异呢,本文我们就分析sys.settrace的整个执行流程。

sys.settrace函数的源码流程

首先,在Python3.5.2的源码中找到sysmodule.c文件,该文件中就是c实现的sys模块的相关函数;

static PyMethodDef sys_methods[] = {
    ...
    {"settrace",        sys_settrace, METH_O, settrace_doc},
    {"gettrace",        sys_gettrace, METH_NOARGS, gettrace_doc},
    ...
    {NULL,              NULL}           /* sentinel */
};

此时调用的sys.settrace函数就是调用了sys_settrace函数;

static PyObject *
sys_settrace(PyObject *self, PyObject *args)
{
    if (trace_init() == -1)                          // 初始化trace
        return NULL;
    if (args == Py_None)
        PyEval_SetTrace(NULL, NULL);                 // 如果初始化传入的函数为None则设置空
    else
        PyEval_SetTrace(trace_trampoline, args);     // 否则设置该函数
    Py_INCREF(Py_None);
    return Py_None;                                  // 返回None
}



static int
trace_init(void)
{
    static char *whatnames[7] = {"call", "exception", "line", "return",
                                    "c_call", "c_exception", "c_return"};       // 定义了7个事件对应的描述字符
    PyObject *name;
    int i;
    for (i = 0; i < 7; ++i) {
        if (whatstrings[i] == NULL) {
            name = PyUnicode_InternFromString(whatnames[i]);                    // 遍历转换为python字符串
            if (name == NULL)
                return -1;
            whatstrings[i] = name;                                              // 设置对应的Python字符串
        }
    }
    return 0;
}

#define PyTrace_CALL 0
#define PyTrace_EXCEPTION 1
#define PyTrace_LINE 2
#define PyTrace_RETURN 3
#define PyT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值