В чем разница между исходными кодами Python3.5 и Python3.6?
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);
?
1 ответ
Вы используете отладочную версию 3.5. В Python 3.5 и любой предыдущей версии нумерация строк в одном блоке байт-кода (т. Е. Байт-код модуля или функции) должна была быть монотонной, то есть каждый код операции должен отображаться на строку в исходном коде, чей номер белья должен быть больше или равно номеру строки предыдущего кода операции. Это когда-либо проверялось в отладочных сборках; в релизных сборках Python assert
не будет скомпилирован, но сгенерированная вкладка номера строки в любом случае была бы недействительной.
Это обсуждалось в выпуске 26107 на http://bugs.python.org/. Требование монотонности номеров строк считалось вредным для оптимизаций, многие из которых реорганизуют сгенерированный байт-код. Таким образом, проверка была удалена в 3.6 вместе с другими изменениями, которые делают дельту номера строки целым числом со знаком.
Вы можете закомментировать это утверждение довольно безопасно, так как сборки релиза в любом случае устранили бы его, но не ожидайте, что отладка будет работать правильно в сгенерированном коде, так как вкладка номера строки теперь недопустима.
В качестве альтернативы, если вы реорганизуете строки в AST или что-то подобное, вы можете установить все номера строк равными 0, а не только отсутствующие; или вы можете генерировать фальшивые номера строк, которые не нарушают правило монотонности.
Случайная проблема возникла с генерируемыми AST, так как ast.fix_missing_locations
написал бы номер строки 0 для любых узлов, у которых не было нумерации строк. Если части AST содержат номера строк, потому что они произошли от ast.parse
, вероятно, что результирующее дерево AST нарушит требование монотонности - что опять-таки приведет только к проблемам на не-релизных сборках Pythons < 3.6.
Другое изменение, которое здесь не относится к ошибке, - это переход от байт-кода к слову-коду, который также был введен в Python 3.6. Здесь каждый код операции будет 16-разрядным словом вместо 8-разрядного байта с возможными расширенными аргументами. Вот почему смещение умножается на sizeof(_Py_CODEUNIT);
,