Как узнать магическое число для заголовка .pyc в Python 3

Файлы байт-кода Python (.pyc) имеют заголовок, который начинается с магического числа, которое изменяется между версиями Python. Как я могу (программно) узнать этот номер для текущей версии Python, чтобы сгенерировать действительный заголовок? В настоящее время я жестко пишу код для Python 3.7.1, но это означает, что теперь я зависим от конкретной версии Python.

Этот ответ делает именно то, что я хочу, используя py_compile.MAGIC, но этого, похоже, больше не существует в Python 3. Как я могу сделать эквивалент в Python 3?

Вот пример того, что я пытаюсь сделать:

import dis
import marshal

PYC_HEADER = b'\x42\x0d\x0d\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

def f():
    print('Hello World')

with open('test.pyc', 'wb') as pyc:
    pyc.write(PYC_HEADER)
    marshal.dump(dis.Bytecode(f).codeobj, pyc)

Это должно создать файл test.pyc, который затем можно будет запустить, используя тот же интерпретатор Python, что и сценарий, и он должен напечатать «Hello World!». И это так, но только при использовании Python 3.7. Я ищу способ, который генерирует заголовок для той версии Python 3, которая используется для запуска скрипта, а не для жесткого кодирования 3.7.

Для контекста:

Я компилирую простой язык программирования для различных форматов байт-кода (LLVM, байт-код Java, веб-сборка, а теперь и байт-код Python) в рамках запланированной серии руководств по созданию компилятора.

Я могу сгенерировать байт-код Python, используя библиотека byteasm, что в результате дает мне функцию. Но для записи содержимого в файл .pyc мне нужен действующий заголовок. За счет жесткого кодирования заголовка код будет работать только в том случае, если люди, следующие руководству, используют ту же версию Python 3, что и я (3.7), или им придется вручную определять магическое число для своей версии.

Эй, как дела. Я действительно очень хочу увидеть вашу серию руководств, но не знаю, где ее найти. Не могли бы вы передать мне ссылку? Спасибо друг

Glubs 25.02.2021 23:32

@Glubs Я сожалею, что так и не успел написать это. Вы можете посмотреть код генератора байт-кода здесь, но имейте в виду, что здесь почти нет комментариев, потому что я решил, что в этом нет необходимости, поскольку я объясню код в блоге, который я так и не написал.

sepp2k 26.02.2021 00:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
16
2
12 792
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Начиная с Python 3.4 в модуле importlib.util.MAGIC_NUMBER есть importlib:

>>> import importlib
>>> importlib.util.MAGIC_NUMBER.hex()
'420d0d0a'

Другое решение для Python <3.4 или Python2 - это get_magic метод модуля imp.

>>> import imp
>>> imp.get_magic().hex()
'420d0d0a'

Обратите внимание, что, хотя это все еще работает в Python 3.7, оно устарело с Python 3.4.

Спасибо, это именно то, что мне было нужно (за исключением .hex(), поскольку он должен входить в файл в виде байтов, а не шестнадцатеричной строки).

sepp2k 18.12.2018 14:13

Он переехал!

>>> import importlib.util
>>> importlib.util.MAGIC_NUMBER
b'3\r\r\n'

Новое в версии 3.4.

Наверное, проще всего обернуть это попыткой /, кроме как вернуться к py_compile.

Я думаю, вы имеете в виду «попробовать / кроме» вместо «попытаться / поймать»;)

LMD 18.12.2018 19:09

Ха, слишком много JavaScript

Josh Lee 18.12.2018 19:27

Другие вопросы по теме