什么';Python3.5和Python3.6的源代码有什么不同?

什么';Python3.5和Python3.6的源代码有什么不同?,python,c,python-3.x,python-internals,Python,C,Python 3.x,Python Internals,当运行我的测试程序时,我得到了一个如上所述的错误。 最后我发现Python3.5和Python3.6的源代码之间几乎没有什么区别。 只有一行: 蟒蛇3.5 testing on ../../test/test_patm.py python: Python/compile.c:4420: int assemble_lnotab(struct assembler *, struct instr *): Assertion `d_lineno >= 0' failed. Aborted P

当运行我的测试程序时,我得到了一个如上所述的错误。 最后我发现Python3.5和Python3.6的源代码之间几乎没有什么区别。 只有一行:

蟒蛇3.5

 testing on ../../test/test_patm.py
python: Python/compile.c:4420: int assemble_lnotab(struct assembler *, 
struct instr *): Assertion `d_lineno >= 0' failed.
Aborted
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;
  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;
  ...
如果我只是删除了断言(d_lineno>=0)

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

这是在上一节中讨论的。行号单调性的要求被认为不利于优化,许多优化会重新组织生成的字节码。因此,在3.6中删除了该检查以及使行号delta成为有符号整数的其他更改

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

另一种方法是,如果您正在重新组织AST中的行或类似的内容,则可以将所有行号设置为0,而不仅仅是缺少的行号;也可以生成不违反单调性规则的伪行号


生成的AST出现了一个巧合的问题,因为会将0的行号写入任何缺少行号的节点。如果AST的某些部分包含行号,因为它们源自
AST.parse
,那么生成的AST树很可能会打破单调性要求——这同样只会导致Pythons<3.6的非发布版本出现问题


另一个与此bug无关的变化是从字节码到wordcode的变化,这也是在Python3.6中引入的。在这里,每个操作码将是一个16位字,而不是一个可能带有扩展参数的8位字节。这就是偏移量乘以
sizeof(_Py_CODEUNIT)的原因

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

这是在上一节中讨论的。行号单调性的要求被认为不利于优化,许多优化会重新组织生成的字节码。因此,在3.6中删除了该检查以及使行号delta成为有符号整数的其他更改

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

另一种方法是,如果您正在重新组织AST中的行或类似的内容,则可以将所有行号设置为0,而不仅仅是缺少的行号;也可以生成不违反单调性规则的伪行号


生成的AST出现了一个巧合的问题,因为会将0的行号写入任何缺少行号的节点。如果AST的某些部分包含行号,因为它们源自
AST.parse
,那么生成的AST树很可能会打破单调性要求——这同样只会导致Pythons<3.6的非发布版本出现问题



另一个与此bug无关的变化是从字节码到wordcode的变化,这也是在Python3.6中引入的。在这里,每个操作码将是一个16位字,而不是一个可能带有扩展参数的8位字节。这就是偏移量乘以
sizeof(_Py_CODEUNIT)的原因

我看到另一个区别,
d字节码
乘以
sizeof(\u Py\u CODEUNIT)
@MartijnPieters这是它的定义<代码>类型定义uint16_t_Py_代码单位lineno
,它可能看起来不正确,但不会导致Python3.6中的任何错误!我看到另一个区别,
d字节码
乘以
sizeof(\u Py\u CODEUNIT)
@MartijnPieters这是它的定义<代码>类型定义uint16_t_Py_代码单位lineno,它可能看起来不正确,但不会导致Python3.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;