python - Python3.5和Python3.6的源码有什么区别?

标签 python c 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

当运行我的测试程序时,我得到了上面给出的错误。 最后发现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); 会怎样?

最佳答案

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

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

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

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


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


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

关于python - Python3.5和Python3.6的源码有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45935451/

相关文章:

python - 我不能在 Python 中使用花括号是真的吗?

python - 我应该如何使用 pyparsing 组织我的函数?

c - 如何扫描 C 中数字的前 2 位数字?

python - 在本地集群上运行 dask 时超时 OSError

python - Pandas - 按组比较当前年份与所有以前年份的值,如果它是累积最小值,则返回 True

Panda Dataframe 的 Python 并发 Future

c - 用于在 C 中重命名文件的 Win32 API

没有警告的 C Unix 程序仍然无法运行

python-3.x - 单一 View 中的多模型表单集工厂

python - 如何将 .py 转换为 .exe?