# PyCodeObj和PyFrameObj

# PyCodeObj和PyFrameObj

  1. pycodeobj 在编译时创建,是静态的。

  2. pyframeobj 在运行时创建,是动态的。一个 pycodeobj 可以对应多个 pyframeobj,每个 pyframeobj 都有一个对应的 pycodeobj。

  3. pycodeobj 主要存储静态信息,例如:

       - co_name            # 对象名称
       - co_argcount        # 参数个数(非函数一般为0)
       - co_code            # 字节码的序列化形式
       - co_consts          # 使用到的常量
       - co_names           # 使用到的名称
       - co_nlocals         # 局部变量个数
       - co_varnames        # 局部变量名称
       - co_flags           # 编译标志
       - co_filename        # 文件名
       - co_firstlineno     # 源代码第一行的行号
       - co_freevars        # 自由变量(未在局部绑定的变量)
       - co_cellvars        # 单元变量(局部作用域但在内嵌函数中使用的变量)-  即闭包变量
       - co_kwonlyargcount  # 仅关键字参数的数量
       - co_posonlyargcount # 仅位置参数的数量
       - co_stacksize       # 执行栈大小
       - co_lnotab          # 行号表
       - co_linetable       # 行号表
       - co_positions       # 字节码中的位置
       - co_lines           # 源代码行号
       - co_qualname        # 对象的限定名称
       - co_exceptiontable  # 异常表
    
  4. pyframeobj 用来存储运行时信息,例如:

       - f_code             # 关联的代码对象
       - f_back             # 调用此帧的帧 - 上一帧
       - f_builtins         # 内置名称空间
       - f_globals          # 全局名称空间
       - f_locals           # 局部名称空间
       - f_lineno           # 当前行号
       - f_lasti            # 最后执行的指令的索引
       - f_trace            # 跟踪函数
       - f_exc_type         # 当前异常类型
       - f_exc_value        # 当前异常值
       - f_exc_traceback    # 当前异常的追溯信息
       - f_restricted       # 是否为受限制的执行
       - f_stacktop         # 值栈的顶部
       - f_valuestack       # 值栈
       - f_blockstack       # 块栈
       - f_localsplus       # 局部变量和其它局部变量存储 - 实际就是运行时的栈
    

# 示例

""" 
>>> text = open("./PyTests/codeobj_test1.py", 'r').read()
>>> text
's = "FFFFF"\n\ndef func(x, y):\n    if x == y:\n        return 0\n    return 1\n\nclass F:\n    pass\n\nfunc()\n\n\n'
>>> code = compile(text, 'cbt', 'exec')
>>> code
<code object <module> at 0x7ff04eaa2d20, file "cbt", line 1>
def print_code(co):
    print(f'co_name:\t{co.co_name}')
    for attr in dir(co):
        if attr[0] != '_':
            print(f'  {attr}:\t{getattr(co,attr)}')
... 
>>> 
def dfs(co):
    print_code(co)
    for c in co.co_consts:
        if isinstance(c, types.CodeType):
            dfs(c)
... 
>>> 
>>> import types
>>> dfs(code)
co_name:        <module>
  co_argcount:  0
  co_cellvars:  ()
  co_code:      b'd\x00Z\x00d\x01d\x02\x84\x00Z\x01G\x00d\x03d\x04\x84\x00d\x04\x83\x02Z\x02e\x01\x83\x00\x01\x00d\x05S\x00'
  co_consts:    ('FFFFF', <code object func at 0x7ff04eaa2780, file "cbt", line 3>, 'func', <code object F at 0x7ff04eaa2c90, file "cbt", line 8>, 'F', None)
  co_filename:  cbt
  co_firstlineno:       1
  co_flags:     64
  co_freevars:  ()
  co_kwonlyargcount:    0
  co_lnotab:    b'\x04\x02\x08\x05\x0e\x03'
  co_name:      <module>
  co_names:     ('s', 'func', 'F')
  co_nlocals:   0
  co_stacksize: 3
  co_varnames:  ()
co_name:        func
  co_argcount:  2
  co_cellvars:  ()
  co_code:      b'|\x00|\x01k\x02r\x0cd\x01S\x00d\x02S\x00'
  co_consts:    (None, 0, 1)
  co_filename:  cbt
  co_firstlineno:       3
  co_flags:     67
  co_freevars:  ()
  co_kwonlyargcount:    0
  co_lnotab:    b'\x00\x01\x08\x01\x04\x01'
  co_name:      func
  co_names:     ()
  co_nlocals:   2
  co_stacksize: 2
  co_varnames:  ('x', 'y')
co_name:        F
  co_argcount:  0
  co_cellvars:  ()
  co_code:      b'e\x00Z\x01d\x00Z\x02d\x01S\x00'
  co_consts:    ('F', None)
  co_filename:  cbt
  co_firstlineno:       8
  co_flags:     64
  co_freevars:  ()
  co_kwonlyargcount:    0
  co_lnotab:    b'\x08\x01'
  co_name:      F
  co_names:     ('__name__', '__module__', '__qualname__')
  co_nlocals:   0
  co_stacksize: 1
  co_varnames:  ()
"""