Comment puis-je générer manuellement un fichier .pyc à partir d'un fichier .py

128

Pour une raison quelconque, je ne peux pas dépendre de l'instruction "import" de Python pour générer automatiquement un fichier .pyc

Existe-t-il un moyen d'implémenter une fonction comme suit?

def py_to_pyc(py_filepath, pyc_filepath):
    ...
zJay
la source

Réponses:

241

Vous pouvez utiliser compilealldans le terminal. La commande suivante ira récursivement dans les sous-répertoires et créera des fichiers pyc pour tous les fichiers python qu'elle trouve. Le module compileall fait partie de la bibliothèque standard python, vous n'avez donc pas besoin d'installer quoi que ce soit de plus pour l'utiliser. Cela fonctionne exactement de la même manière pour python2 et python3.

python -m compileall .
Marwan Alsabbagh
la source
4
Cela devrait être la réponse acceptée - du moins dans mon besoin de compiler tous les * .py dans * .pyc: récursivement :)
swdev
1
Est-il possible de distribuer un fichier PYC contenant toutes les bibliothèques utilisées? Donc, les utilisateurs n'ont pas à les installer, ils ont juste exécuté le fichier PYC, je sais qu'en java, cela est possible en utilisant un JAR. Existe-t-il une méthode similaire pour Python?
D.Snap
J'ai aussi entendu quelque chose sur les fichiers méta en Python. Cette compilation crée-t-elle également un cache? Sinon, quelle est la commande pour cela ?? Puisque les utilisateurs finaux n'ont pas l'autorisation d'écriture sur le répertoire lib. Et je veux accélérer les choses ici ... PS. jetez également un œil à l' -Oindicateur, pour la compilation bytecode (fichier .pyo iso .pyc).
danger89
qu'en est-il de la décompilation?
Sajuuk
1
soyez prudent avec cette commande. J'ai accidentellement fait un compileallsur mon dossier site-packages et cela a tout gâché
Alex
58

Vous pouvez compiler des fichiers individuels à partir de la ligne de commande avec:

python -m compileall <file_1>.py <file_n>.py
derrend
la source
55

Cela fait un moment que j'ai utilisé Python pour la dernière fois, mais je pense que vous pouvez utiliser py_compile:

import py_compile
py_compile.compile("file.py")
Mike Bailey
la source
8
Vous souhaiterez probablement inclure le deuxième paramètre, qui détermine le fichier de sortie. Sinon, la valeur par défaut est quelque chose comme __pycache__/file.cpython-32.pycet vous obtenez cela comme valeur de retour.
rvighne
46

J'ai trouvé plusieurs façons de compiler des scripts python en bytecode

  1. Utilisation py_compiledans le terminal:

    python -m py_compile File1.py File2.py File3.py ...

    -m spécifie le nom du ou des modules à compiler.

    Ou, pour la compilation interactive de fichiers

    python -m py_compile -
    File1.py
    File2.py
    File3.py
       .
       .
       .
  2. Utilisation py_compile.compile:

    import py_compile
    py_compile.compile('YourFileName.py')
  3. Utilisation py_compile.main():

    Il compile plusieurs fichiers à la fois.

    import py_compile
    py_compile.main(['File1.py','File2.py','File3.py'])

    La liste peut s'allonger aussi longtemps que vous le souhaitez. Alternativement, vous pouvez évidemment passer une liste de fichiers dans les noms de fichiers principaux ou même dans les arguments de ligne de commande.

    Ou, si vous passez ['-']dans main, il peut compiler des fichiers de manière interactive.

  4. Utilisation compileall.compile_dir():

    import compileall
    compileall.compile_dir(direname)

    Il compile chaque fichier Python présent dans le répertoire fourni.

  5. Utilisation compileall.compile_file():

    import compileall
    compileall.compile_file('YourFileName.py')

Jetez un œil aux liens ci-dessous:

https://docs.python.org/3/library/py_compile.html

https://docs.python.org/3/library/compileall.html

Abhishek Kashyap
la source
Une petite correction est que le nom du module que vous chargez est py_compileet compileallNON py_compile.pyou compileall.py. En d'autres termes, cela devrait être python3 -m py_compile PYTHON_FILENAMEou python3 -m compileall PYTHON_FILES_DIRECTORY.
Devy
17

J'utiliserais compileall . Cela fonctionne bien à la fois à partir de scripts et de la ligne de commande. C'est un module / outil de niveau un peu plus élevé que le py_compile déjà mentionné qu'il utilise également en interne.

Pekka Klärck
la source
compilealln'inclut pas de logique pour ignorer les fichiers pour lesquels le .pycfichier correspondant est déjà à jour, n'est-ce pas?
Kyle Strand
2
@KyleStrand ignore compileallles fichiers qui ont déjà une mise à jour .pyc(testé avec Python 2.7.11)
Éponyme
@Eponymous Intéressant. Je ne sais pas pourquoi j'ai pensé le contraire. Merci d'avoir vérifié.
Kyle Strand
6

En Python2, vous pouvez utiliser:

python -m compileall <pythonic-project-name>

ce qui rend compilent tout .pyà .pycdans le projet qui contient les sous - dossiers.


En Python3, vous pouvez utiliser:

python3 -m compileall <pythonic-project-name>

ce qui fait tout compiler .pyvers le__pycache__ dossiers du projet qui contenaient les sous-dossiers.

Ou avec le brunissement de ce post :

Vous pouvez appliquer la même disposition de .pycfichiers dans les dossiers que dans Python2 en utilisant:

python3 -m compileall -b <pythonic-project-name>

L'option -bdéclenche la sortie des .pycfichiers vers leurs anciens emplacements (c'est-à-dire le même que dans Python2).

Benyamin Jafari
la source
3

Pour correspondre aux exigences de la question d'origine (chemin source et chemin de destination), le code doit être comme ça:

import py_compile
py_compile.compile(py_filepath, pyc_filepath)

Si le code d'entrée contient des erreurs, l' exception py_compile.PyCompileError est déclenchée .

ababak
la source
1

Il y a deux façons de faire cela

  1. Ligne de commande
  2. Utilisation du programme python

Si vous utilisez la ligne de commande, utilisez python -m compileall <argument>pour compiler du code python en code binaire python. Ex:python -m compileall -x ./*

Ou, vous pouvez utiliser ce code pour compiler votre bibliothèque en byte-code.

import compileall
import os

lib_path = "your_lib_path"
build_path = "your-dest_path"

compileall.compile_dir(lib_path, force=True, legacy=True)

def compile(cu_path):
    for file in os.listdir(cu_path):
        if os.path.isdir(os.path.join(cu_path, file)):
            compile(os.path.join(cu_path, file))
        elif file.endswith(".pyc"):
            dest = os.path.join(build_path, cu_path ,file)
            os.makedirs(os.path.dirname(dest), exist_ok=True)
            os.rename(os.path.join(cu_path, file), dest)

compile(lib_path)

regardez ☞ docs.python.org pour une documentation détaillée

Prashant
la source