Excel 名称框概述-英雄云拓展知识分享
127
2023-11-07
【摘要】 本书摘自《自己动手写 Python 虚拟机》一书中第6章,第2节,海纳编著。
6.2.2 函数的参数
函数最重要的功能就是接受参数、进行运算和返回计算结果。上一节展示了函 数如何创建栈帧、进行运算并且返回计算结果的。这一节关注如何向一个函数传递 参数。
Python 中传递参数的机制比很多语言都要复杂,所以参数的实现放在最后讲。 与以前的方法相同,先写测试用例,再观察例子所对应的字节码。创建 test_param. py 如代码清单6.15 所示。
首先,在这一段反编译字节码里,CALL_FUNCTION 与上一节有所不同。上一 节中的函数调用都没有带参数,所以这个字节码的参数就是0,在这一节的 add 例子 里,函数调用传递了两个参数,所以这个字节码的参数是2。实际上,在 CALL FUNCTION 之前的两个字节码已经把参数送到栈上了,接下来要做的,只是根据 CALL_FUNCTION 的参数将栈上的值取出来,然后再传给函数栈帧就好了。因此, 在 FrameObject 里增加可以接受参数的功能
=func ->_func_code;
=_codes ->_consts;
=_codes ->_names;
_locals =new Map
_globals =func ->_globals;
_fast_locals =NULL;
10
if(args){
_fast_locals =new ArrayList
13
for(inti=0;i_fast_locals->set(i,args>get(i));
16
17
18
_stack =new ArrayList
_loop_stack =new ArrayList
21
22
23
24
25
26
_frame =frame;
}
32
void Interpreter:;run(CodeObject*codes){
_frame =new FrameObject(codes);
while(_frame->has_more_codes()){
unsigned char op_ccde =_frame >get_op_code();
switch(op_code){
39
case ByteCode::CALL_FUNCTION:
if(op_arg>0){
args =new ArrayList
while(op_arg--){
第41~46行,根据 op_arg 去栈里取出参数,然后将所有的参数以 ArrayList 的 形式传递给 build_frame 。 第27和28行,把函数的参数传递到了 FrameObject 中。 为 FrameObject 的构造函数增加了新的参数,用于表示调用函数时所使用的参数。 第11~17行,将传入的参数放到_fast_locals 中去。这样,就把函数的参数传到函数 中去了。
当函数参数被传到_fast_locals 中去以后,接着就是执行函数了。add 方法的前 两条字节码是 LOAD_FAST, 而 LOAD_FAST 与 LOAD_NAME 、LOAD_CONST 一样,都是往栈上加载一个值(本质上是一个对象),区别在于,是从哪里读取值。 LOAD_CONST 是从 consts 里加载,LOAD_NAME 是从局部变量表里加载,而
LOAD_FAST 6.16所示。
添加了这些修改以后,就可以测试了,本节刚开始的 test_param 的例子可以正 常执行了。运行以后,可以输出3。至此,就完成了函数调用的传参功能。
6.2.3 参数默认值
在定义函数的时候,可以为函数的参数指定默认值。代码清单6.17展示了这样 一个例子。
在调用foo 方法时,如果传的参数刚好就是1,则可以不必给出实参的值。如果 不想让形参取此默认值,则可以通过实参另行给出,这种方式可以简化编程。
思考一下如何在虚拟机里实现这个功能。默认值应该是在函数定义的时候就和 函数绑在一起了,因此, 一定是在 MAKE_FUNCTION 处来实现默认值的功能。
在 MAKE_FUNCTION 处创建FunctionObject, 所以默认值的最佳载体显然是 FunctionObject 。 只需要把默认值记录在 FunctionObject 里,在调用的时候再加以 处理即可。
先做第一件事情,在 FunctionObject 里增加一个域,用于记录函数参数的默认 值
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们 18664393530@aliyun.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~