Python3.5和Python3.6的源代码之间有什么区别?

mis*_*awa 1 c python python-3.x python-internals

 testing on ../../test/test_patm.py
python: Python/compile.c:4420: int assemble_lnotab(struct assembler *, 
struct instr *): Assertion `d_lineno >= 0' failed.
Aborted
Run Code Online (Sandbox Code Playgroud)

运行我的测试程序时,我收到了上面给出的错误.最后我发现Python3.5和Python3.6的源代码差别很小.只需一行:

Python3.5

static int
assemble_lnotab(struct assembler *a, struct instr *i)
{
  int d_bytecode, d_lineno;
  Py_ssize_t len;
  unsigned char *lnotab;

  d_bytecode = a->a_offset - a->a_lineno_off;
  d_lineno = i->i_lineno - a->a_lineno;

  assert(d_bytecode >= 0);
  assert(d_lineno >= 0);   // the only difference

  if(d_bytecode == 0 && d_lineno == 0)
      return 1;
  ...
Run Code Online (Sandbox Code Playgroud)

Python 3.6

static int
assemble_lnotab(struct assembler *a, struct instr *i)
{
    int d_bytecode, d_lineno;
    Py_ssize_t len;
    unsigned char *lnotab;

    d_bytecode = (a->a_offset - a->a_lineno_off) * sizeof(_Py_CODEUNIT);
    d_lineno = i->i_lineno - a->a_lineno;

    assert(d_bytecode >= 0);

    if(d_bytecode == 0 && d_lineno == 0)
        return 1;
Run Code Online (Sandbox Code Playgroud)

如果我刚删除assert(d_lineno >= 0);怎么办?

Ant*_*ala 7

您正在使用3.5 的调试版本.在Python 3.5和任何以前的版本中,单个字节码块中的行编号(即模块的字节码或函数)必须是单调的,即每个操作码必须映射到源代码中的行,其中亚麻码必须是大于或等于前一个操作码的行号.在调试版本中检查过这个问题; 在Python的发布版本中,assert不会编译,但生成的行号选项卡无论如何都是无效的.

有关bugs.python.org的问题26107 对此进行了讨论.对行数单调性的要求被认为对优化有害,其中许多将重新组织生成的字节码.因此,在3.6中删除了检查以及使行号delta为有符号整数的其他更改.

您可以非常安全地注释掉这个断言,因为版本构建无论如何都会消除它,但是不要期望调试在生成的代码中正常工作,因为行号选项卡现在无效.

作为替代方案,如果您重新组织AST中的行或类似的行,您可以将所有行号设置为0 - 而不仅仅是丢失的行号; 或者你可以生成不违反单调性规则的假行号.


生成的AST出现了巧合问题,因为它 ast.fix_missing_locations会将行号0写入缺少行号的任何节点.如果AST的某些部分包含因为它们来源的行号ast.parse,那么生成的AST树很可能会破坏单调性要求 - 这也只会导致Pythons <3.6的非释放构建出现问题.


与此处的错误无关的另一个变化是从字节码到字代码的变化,这也是在Python 3.6中引入的.这里每个操作码都是一个16位字,而不是一个8位字节,可能有扩展的args.这就是偏移量乘以的原因sizeof(_Py_CODEUNIT);.