The function mechanism of Python virtual machine (ii)

Source: Internet
Author: User
Tags strcmp

Namespaces when functions are executed

In the chapter on the function mechanism of the Python virtual machine (a), we have a general understanding of the function invocation mechanism in Python, and on that basis, let's look at some details. When executing the make_function instruction, the Pyfunction_new method is called, and the method has a parameter of globals, and this globals will eventually be called the global namespace in the pyframeobject corresponding to function f--f_ Globals

Ceval.c

Case make_function:v = POP (); /* Code Object */x = Pyfunction_new (V, f->f_globals); Py_decref (v);/* XXX Maybe this should is a separate opcode? */if (x = null && oparg > 0) {v = pytuple_new (Oparg), if (v = = null) {py_decref (x); x = Null;break;} while (--oparg >= 0) {w = POP (); Pytuple_set_item (V, Oparg, W);} Err = pyfunction_setdefaults (x, v); Py_decref (v);} PUSH (x); break;

 

# cat Demo.pydef F ():    print ("Function")  f () # python2.5......>>> Source = open ("demo.py"). Read () >> > CO = compile (source, "demo.py", "exec") >>> import dis>>> Dis.dis (CO)  1           0 load_const               0 (<code object f at 0x7fd9831c3648, file "demo.py", line 1>)              3 make_function            0              6 store_name               0 (f) 
   5           9 load_name                0 (f)             call_function            0             pop_top                         load_const               1 (None)             Return_value       >>> from demo import ffunction>>> Dis.dis (f)  2           0 load_const               1 (' Function ')              3 print_item                       4 print_newline                    5 load_const               0 (None)              

  

In the general expression in the Python virtual machine (iii), we describe the load_name directive, which, in turn, searches from three Pydictobject objects sequentially, with the search order: f_locals, F_globals, F_builtins. The incoming globals at Pyfunction_new becomes the global namespace that executes the function in the new stack frame. In Make_function, we see that the incoming Globals parameter is f_globals in the current Pyframeobject object. This means that The global namespace, when executing the demo.py bytecode instruction, is actually the same namespace as the global namespace when the byte code sequence of the function f is executed, which is passed along with the Pycodeobject object corresponding to the bytecode instruction, which is carried by Pyfunctionobject. To the new stack frame

Below, let's modify the implementation of the Make_function directive and the call_function to output the address and content of the global namespace

Ceval.c

Case make_function:v = POP (); /* Code object */char *v_co_name = Pystring_asstring (((Pycodeobject *) v)->co_name); if (strcmp (V_co_name, "f") = = 0) {if (stream = = NULL | | stream = = py_none) {w = pysys_getobject ("stdout"), if (w = = NULL) {pyerr_setstring (Pyexc_runtimeerror, "lost Sys.stdout"); err =-1;}} Print the address of the Globals namespace printf ("[Make_function]:f_globals addr:%p\n", f->f_globals);//Print the contents of the Globals namespace printf ("[Make _function]: "); Pyfile_writeobject (F->f_globals, W, Py_print_raw);p rintf ("\ n"); stream = NULL;}  x = Pyfunction_new (v, f->f_globals); static Pyobject * Call_function (pyobject ***pp_stack, int oparg) {int na = Oparg & 0xff;int NK = (oparg>>8) & 0xff;int n = Na + 2 * NK; Pyobject **pfunc = (*pp_stack)-n-1; Pyobject *func = *pfunc; Pyobject *x, *w;char *func_name = Pyeval_getfuncname (func); if (strcmp (Func_name, "f") = = 0) {Pyobject *std = Pysys_getobjec T ("stdout");//Gets the global namespace corresponding to the function pyobject *func_globals = (Pycodeobject *) Pyfunction_get_globals (func);// Print the Globals namespacesAddress printf ("[Call_function]:func_globals addr:%p\n", func_globals);//Print the contents of the Globals namespace printf ("[Call_function]:"); Pyfile_writeobject (func_globals, STD, Py_print_raw);p rintf ("\ n");} ......}

  

Then we execute the demo1.py file.

# cat demo1.py A = 1b = 3def f ():    print ("function f") def g ():    print ("function g") f () # python2.5 demo1.py [Make_fun Ction]:f_globals addr:0x2237740[make_function]:{' A ': 1, ' B ': 3, ' __builtins__ ': <module ' __builtin__ ' (built-in) , ' __file__ ': ' demo1.py ', ' __name__ ': ' __main__ ', ' __doc__ ': None}[call_function]:func_globals addr:0x2237740[ call_function]:{' A ': 1, ' B ': 3, ' G ': <function g at 0x7f54708c7de8>, ' F ': <function f at 0x7f54708c7b18>, ' __b Uiltins__ ': <module ' __builtin__ ' (built-in), ' __file__ ': ' demo1.py ', ' __name__ ': ' __main__ ', ' __doc__ ': None} Function F

  

As you can see, the address of the global namespace in Make_function and Call_function is the same, and the symbols defined in demo1.py are included in the global namespace so that function f can use a, b two variables, It relies on the transfer of the global namespace to allow function f to use symbols other than function f. Now, let's look at the Globals content in [make_function] and [call_function] separately, and we'll find that the former has no functions f and G, the latter has functions f and G, and the addresses of the two are the same. This means that when the bytecode instruction executes, the function f and G must be put into the global namespace, otherwise, the function cannot find its own definition in global and cannot implement recursion, although our function f is not recursive here.

So, when does the function f and G sneak into the global namespace? We use the DIS module to see the demo1.py source code corresponding bytecode instructions

[Email protected] python]# python2.5......>>> Source = open ("demo1.py"). Read () >>> CO = compile (source, "              demo1.py "," exec ") >>> import dis>>> Dis.dis (CO) 1 0 load_const 0 (1)               3 Store_name 0 (a) 2 6 Load_const 1 (3) 9 Store_name             1 (b) 5 Load_const 2 (<code object f at 0x7f5d0aa74648, file ' demo1.py ', line 5>)  Make_function 0 Store_name 2 (f) 9 Load_const 3             (<code object g at 0x7f5d0aa74918, file "demo1.py", line 9>) make_function 0             3 Store_name (g) Load_name 2 (f) call_function 0 Pop_top Notoginseng load_const 4 (None) Return_value

  

We see the "Make_function 0" and "make_function 0" instructions, both of which are executing DEF statements to create Pyfunctionobject objects, make_function instructions to create Pyfunctionobj After the ECT object is pressed into the stack, it is clear that the mapping of the symbol F and G to the Pyfunctionobject object in the global namespace is not make_function. So we look back, the two instructions are followed by "Store_name 2 (f)" and "Store_name 3 (g)", will it be here to establish the symbol and function object mapping? Let's look at the implementation of Store_name:

Ceval.c

Case store_name:w = GETITEM (names, oparg), V = POP (), if ((x = f->f_locals)! = NULL) {if (Pydict_checkexact (x)) Err = Pydic T_setitem (x, W, v); elseerr = Pyobject_setitem (x, W, v); Py_decref (v); if (err = = 0) continue;break;} Pyerr_format (Pyexc_systemerror, "No locals found when storing%s", Pyobject_repr (w));

  

Here we see that Store_name will make a map of the local namespace and its values, but not the global namespace we talked about! So, is this the place to do the mapping of symbols and functions? The answer is: the mapping of symbols and functions is done in store_name. It also exposes a message, The local namespace and the global namespace that the demo1.py executes are actually an object, as is the case, because the local namespace of the function stores the locally variable within the function, and global stores the variable outside the function, and the local namespace of the script itself stores the Is the variable of the script itself, what about the global namespace? There is no choice but to use a Pydictobject object in conjunction with the local namespace of the script itself.

The function mechanism of Python virtual machine (ii)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.