您的位置 首页 java

如何查看函数的调用关系?(自省的能力)

Golang

看golang 的runtime包的时候发现可以直接使用runtime.caller看到函数调用关系:

如何查看函数的调用关系?(自省的能力)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

 package main

 import (
	 "fmt"
	 "runtime"
 )

 func main() {
	 for i:=0; i < 4; i++ {
		 test(i)
	 }
 }

 func test(skip int) {
	 call(skip)
 }

 func call(skip int) {
	pc,file,line,ok := runtime.Caller(skip)
	pcName := runtime.FuncForPC(pc).Name()  //获取函数名
	fmt.Println(fmt.Sprintf("%v   %s   %d   %t   %s",pc,file,line,ok,pcName))
 }  
如何查看函数的调用关系?(自省的能力)

编辑切换为居中

添加图片注释,不超过 140 字(可选)

分析结果可以看到0-3分别上当前函数,当前函数的上一个caller,….

Javascript / Nodejs

这样我就思维打开了,我们用过 C 等语言的 JavaScript 开发人员经常错过使用某些类型的自省的能力,例如 记录行号 ,以及 当前方法是从哪个方法调用 的。 好吧,如果您使用的是 V8(Chrome、Node.js),有哪些方法呢?

node.js通过Error.prepareStackTrace获取上层调用函数的文件名地址和行数位置

 
/**
 * Use CallSite to extract filename and number, for more info read: #customizing-stack-traces
 * @returns {string} filename and line number separated by a colon
 */
const getFileNameAndLineNumber = () => {
    const oldStackTrace = Error.prepareStackTrace;
    try {
        // eslint-disable-next-line handle-callback-err
        Error.prepareStackTrace = (err, structuredStackTrace) => structuredStackTrace;
        Error.captureStackTrace(this);
        // in this example I needed to "peel" the first CallSites in order to get to the caller we're looking for
        // in your code, the number of stacks depends on the levels of abstractions you're using
        // in my code I'm stripping frames that come from logger module and winston (node_module)
        const callSite = this.stack.find(line => line.getFileName().indexOf('/logger/') < 0 && line.getFileName().indexOf('/node_modules/') < 0);
        return callSite.getFileName() + ':' + callSite.getLineNumber();
    } finally {
        Error.prepareStackTrace = oldStackTrace;
    }
};  

或者

您可以添加一些原型以提供从 V8 访问此信息的权限:

 
Object.defineProperty(global, '__stack', {
get: function() {
        var orig = Error.prepareStackTrace;
        Error.prepareStackTrace = function(_, stack) {
            return stack;
        };
        var err = new Error;
        Error.captureStackTrace(err, arguments.callee);
        var stack = err.stack;
        Error.prepareStackTrace = orig;
        return stack;
    }
});

Object.defineProperty(global, '__line', {
get: function() {
        return __stack[1].getLineNumber();
    }
});

Object.defineProperty(global, '__function', {
get: function() {
        return __stack[1].getFunctionName();
    }
});

function foo() {
    console.log(__line);
    console.log(__function);
}

foo()  

与 arguments.callee.caller 结合使用,您可以更接近通过宏在 C 中获得的有用日志类型

Python

那么我们在python中怎么办呢? 如何在被调用的方法中获取调用者的方法名?

inspect.getframeinfo 和 inspect 中的其他相关函数可以帮助:

 >>> import inspect
>>> def f1(): f2()
... 
>>> def f2():
...   curframe = inspect.currentframe()
...   calframe = inspect.getouterframes(curframe, 2)
...   print('caller name:', calframe[1][3])
... 
>>> f1()
caller name: f1  

注意! 这种自省旨在帮助调试和开发;不建议将其用于生产功能目的。

参考

文章来源:智云一二三科技

文章标题:如何查看函数的调用关系?(自省的能力)

文章地址:https://www.zhihuclub.com/178299.shtml

关于作者: 智云科技

热门文章

网站地图