web-dev-qa-db-fra.com

Comment trouver le nombre magique pour l'en-tête .pyc dans Python 3

Les fichiers de bytecode Python (.pyc) ont un en-tête qui commence par un nombre magique qui change entre les versions Python. Comment puis-je (par programme) trouver ce numéro pour le Python version afin de générer un en-tête valide? Je suis en train de coder en dur celui pour Python 3.7.1, mais cela signifie que je dépend maintenant d'un Python.

Cette réponse fait exactement ce que je veux en utilisant py_compile.MAGIC, mais cela ne semble plus exister dans Python 3. Comment puis-je faire l'équivalent dans Python 3?

Voici un exemple de ce que j'essaie de faire:

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)

Cela devrait créer un fichier test.pyc, qui peut ensuite être exécuté, en utilisant le même interpréteur Python que le script, et devrait afficher "Hello World!". Et c'est le cas, mais uniquement lorsque vous utilisez Python 3.7. Je cherche un moyen de générer l'en-tête pour la version de Python 3 utilisée pour exécuter le script, plutôt que de coder en dur 3.7.

Pour le contexte:

Je compile un langage de programmation simple dans différents formats de bytecode (LLVM, Java bytecode, Web Assembly et maintenant Python bytecode) dans le cadre d'une série de didacticiels prévus) sur la construction du compilateur.

Je peux générer le Python bytecode en utilisant la bibliothèque byteasm , ce qui me donne une fonction en résultat. Mais pour écrire le contenu dans un .pyc fichier, j'ai besoin d'un en-tête valide. En codant en dur l'en-tête, le code ne fonctionnera que si les personnes qui suivent le didacticiel exécutent la même version de Python 3 que moi (3.7) ou qu'elles devraient le découvrir manuellement le nombre magique pour leur version.

12
sepp2k

Depuis Python 3.4 il y a importlib.util.MAGIC_NUMBER dans le module importlib:

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

Une autre solution pour Python <3.4 ou Python2 est le get_magic méthode du module imp .

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

Notez que bien que cela fonctionne toujours dans Python 3.7, il est déconseillé depuis Python 3.4

9
kalehmann

Ça bouge!1

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

Nouveau dans la version 3.4.

Probablement le plus simple pour envelopper cela dans un essai/sauf pour revenir à py_compile.

8
Josh Lee