• Python程序执行原理


    1.首先在code.h中查看PyCodeObject的struct

     1 typedef struct {
     2     PyObject_HEAD
     3     int co_argcount;        /* #arguments, except *args */
     4     int co_nlocals;        /* #local variables */
     5     int co_stacksize;        /* #entries needed for evaluation stack */
     6     int co_flags;        /* CO_..., see below */
     7     PyObject *co_code;        /* instruction opcodes */
     8     PyObject *co_consts;    /* list (constants used) */
     9     PyObject *co_names;        /* list of strings (names used) */
    10     PyObject *co_varnames;    /* tuple of strings (local variable names) */
    11     PyObject *co_freevars;    /* tuple of strings (free variable names) */
    12     PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
    13     /* The rest doesn't count for hash/cmp */
    14     PyObject *co_filename;    /* string (where it was loaded from) */
    15     PyObject *co_name;        /* string (name, for reference) */
    16     int co_firstlineno;        /* first source line number */
    17     PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) See
    18                    Objects/lnotab_notes.txt for details. */
    19     void *co_zombieframe;     /* for optimization only (see frameobject.c) */
    20     PyObject *co_weakreflist;   /* to support weakrefs to code objects */
    21 } PyCodeObject;
    View Code

    2.加载模块时,模块对应的PyCodeObject对象会被写入 .pyc中,当然在平时的运行代码的过程中,看不到 .pyc文件,

    这个过程必须Python 中库函数compile,具体格式如:compile(source, filename, model[, flags[, dont_inherit]])

    其中:

    source是字符串或AST(abstract sytnax tree)对象.

    filename是文件名,如果不是从文件中读出的代码,可传递一些可辨认的值

    model是编译参数,有eval,signal,exec。处理的对象不同

    后面参数可选

    3.测试

    (1)PyCodeObject

    文件pycodeobject.py

    1 #-*-codeing:UTF-8-*-
    2 s = "hello the cruel world"
    3 def func():
    4     print s
    5 func()
    View Code

    在Python交互式shell里编译代码得到PyCodeObject对象:

    >>> src = open("./code/pycodeobject.py").read()
    >>> co = compile(src,"pycodeobject.py",'exec')
    >>> dir(co)
    ['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
    >>> 
    View Code

    pycodeobjec.py的PyCodeObject对象,print即可

    >>> print co.co_argcount
    0
    >>> print co.co_nlocals
    0
    >>> print co.co_names
    ('s', 'func')
    >>> print co.co_varnames
    ()
    >>> print co.co_consts
    ('hello the cruel world', <code object func at 02118A88, file "pycodeobject.py", line 3>, None)
    >>> print co.co_code
    d
    View Code

    解析指令序列

    >>> import dis
    >>> print dis.dis(co)
      2           0 LOAD_CONST               0 ('hello the cruel world')
                  3 STORE_NAME               0 (s)
    
      3           6 LOAD_CONST               1 (<code object func at 02118A88, file "pycodeobject.py", line 3>)
                  9 MAKE_FUNCTION            0
                 12 STORE_NAME               1 (func)
    
      5          15 LOAD_NAME                1 (func)
                 18 CALL_FUNCTION            0
                 21 POP_TOP             
                 22 LOAD_CONST               2 (None)
                 25 RETURN_VALUE        
    None
    >>> 
    View Code

    第一列表示以下几个指令在py文件中的行号;

    第二列是该指令在指令序列co_code里的偏移量;

    第三列是指令opcode的名称,分为有操作数和无操作数两种,opcode在指令序列中是一个字节的整数;

    第四列是操作数oparg,在指令序列中占两个字节,基本都是co_consts或者co_names的下标;

    第五列带括号的是操作数说明。

    (3)PyFrameObject

    在frameobject.h查看PyFrameObject对象的数据结构

     1 typedef struct _frame {
     2     PyObject_VAR_HEAD
     3     struct _frame *f_back;    /* previous frame, or NULL */
     4     PyCodeObject *f_code;    /* code segment */
     5     PyObject *f_builtins;    /* builtin symbol table (PyDictObject) */
     6     PyObject *f_globals;    /* global symbol table (PyDictObject) */
     7     PyObject *f_locals;        /* local symbol table (any mapping) */
     8     PyObject **f_valuestack;    /* points after the last local */
     9     /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
    10        Frame evaluation usually NULLs it, but a frame that yields sets it
    11        to the current stack top. */
    12     PyObject **f_stacktop;
    13     PyObject *f_trace;        /* Trace function */
    14 
    15     /* If an exception is raised in this frame, the next three are used to
    16      * record the exception info (if any) originally in the thread state.  See
    17      * comments before set_exc_info() -- it's not obvious.
    18      * Invariant:  if _type is NULL, then so are _value and _traceback.
    19      * Desired invariant:  all three are NULL, or all three are non-NULL.  That
    20      * one isn't currently true, but "should be".
    21      */
    22     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
    23 
    24     PyThreadState *f_tstate;
    25     int f_lasti;        /* Last instruction if called */
    26     /* Call PyFrame_GetLineNumber() instead of reading this field
    27        directly.  As of 2.3 f_lineno is only valid when tracing is
    28        active (i.e. when f_trace is set).  At other times we use
    29        PyCode_Addr2Line to calculate the line from the current
    30        bytecode index. */
    31     int f_lineno;        /* Current line number */
    32     int f_iblock;        /* index in f_blockstack */
    33     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
    34     PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
    35 } PyFrameObject;
    View Code

    查看栈帧

    1 def func():
    2     import sys
    3     frame = sys._getframe()
    4     print frame.f_locals
    5     print frame.f_globals
    6     print frame.f_back.f_locals
    7     #你可以打印frame的各个域
    8     print s
    View Code

    此次的代码解析来自Python 2.7版本。

  • 相关阅读:
    extjs grid renderer用法
    EventListenerList举例
    SQL语句的执行原理
    WPF操作邮箱,发送邮件
    wpf中DataGrid行色变换
    JS获取浏览器和荧屏分辨率
    将数据库的二进制字节转换成图片
    字符串操作类
    ios推送基于YII第三方组件的类库
    数组操作类
  • 原文地址:https://www.cnblogs.com/sxmcACM/p/4034214.html
Copyright © 2020-2023  润新知