【问题标题】:What's the difference here between the source codes of Python3.5 and Python3.6?Python3.5和Python3.6的源代码在这里有什么区别?
【发布时间】:2017-08-29 09:29:09
【问题描述】:
 testing on ../../test/test_patm.py
python: Python/compile.c:4420: int assemble_lnotab(struct assembler *, 
struct instr *): Assertion `d_lineno >= 0' failed.
Aborted

在运行我的测试程序时,我收到了上面给出的错误。 最后我发现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;
  ...

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;

如果我刚刚删除了assert(d_lineno >= 0);,会怎样?

【问题讨论】:

  • 我看到另一个区别,d_bytecode 乘以 sizeof(_Py_CODEUNIT)
  • @MartijnPieters 这是它的定义。 typedef uint16_t _Py_CODEUNIT;
  • 那么你的代码是什么,为什么会触发断言错误呢?我不会从 Python 代码中删除断言,不,它表明你有一个错误 elsewhere
  • 你在 3.6 上测试过你的程序吗?
  • @MartijnPieters 为什么我的代码导致这个问题是我没有更改ast的lineno,它可能看起来不正确,但它不会导致Python3.6中的任何错误!

标签: python c python-3.x python-internals


【解决方案1】:

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

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

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

作为替代方案,如果您正在重新组织 AST 中的行或类似的东西,您可以将 all 行号设置为 0 - 而不仅仅是缺少的行号;或者您可以生成不违反单调性规则的假行号。


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


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

【讨论】:

    猜你喜欢
    • 2015-05-30
    • 1970-01-01
    • 2022-01-25
    • 2014-09-28
    • 2012-09-27
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    相关资源
    最近更新 更多