Jak ręcznie wygenerować plik .pyc z pliku .py

135

Z jakiegoś powodu nie mogę polegać na instrukcji „import” w języku Python, która automatycznie wygeneruje plik .pyc

Czy istnieje sposób na zaimplementowanie następującej funkcji?

def py_to_pyc(py_filepath, pyc_filepath):
    ...
zJay
źródło

Odpowiedzi:

250

Możesz użyć compileallw terminalu. Następujące polecenie przejdzie rekurencyjnie do podkatalogów i utworzy pliki pyc dla wszystkich znalezionych plików Pythona. Compileall moduł jest częścią standardowej biblioteki Pythona, więc nie ma potrzeby instalowania żadnych dodatków, aby go używać. Działa to dokładnie w ten sam sposób w przypadku python2 i python3.

python -m compileall .
Marwan Alsabbagh
źródło
4
To powinna być akceptowana odpowiedź - przynajmniej w mojej potrzebie skompilowania wszystkich * .py do * .pyc: rekurencyjnie :)
swdev
1
Czy można rozpowszechniać plik PYC zawierający wszystkie używane biblioteki? Więc użytkownicy nie muszą ich instalować, po prostu uruchomili plik PYC, wiem, że w Javie jest to możliwe przy użyciu plików JAR, czy jest jakaś podobna metoda dla Pythona?
D.Snap
Słyszałem też coś o metaplikach w Pythonie. Ta kompilacja również buduje pamięć podręczną? Jeśli nie, jakie jest polecenie? Ponieważ użytkownicy końcowi nie mają uprawnień do zapisu w katalogu lib. I chcę tu przyspieszyć ... PS. spójrz również na -Oflagę kompilacji kodu bajtowego (plik .pyo iso .pyc).
niebezpieczeństwo89
a co z dekompilacją?
Sajuuk
1
uważaj na to polecenie. Przypadkowo zrobiłem w compileallfolderze z pakietami witryn i wszystko zepsuło
Alex
62

Możesz skompilować pojedyncze pliki z wiersza poleceń za pomocą:

python -m compileall <file_1>.py <file_n>.py
derrend
źródło
57

Minęło trochę czasu, odkąd ostatnio korzystałem z Pythona, ale uważam, że możesz użyć py_compile:

import py_compile
py_compile.compile("file.py")
Mike Bailey
źródło
8
Prawdopodobnie chcesz dołączyć drugi parametr, który określa plik wyjściowy. W przeciwnym razie domyślnie jest to coś podobnego __pycache__/file.cpython-32.pyci otrzymasz to jako wartość zwracaną.
rvighne
47

Znalazłem kilka sposobów kompilacji skryptów Pythona do kodu bajtowego

  1. Korzystanie py_compilew terminalu:

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

    -m określa nazwy modułów do skompilowania.

    Lub do interaktywnej kompilacji plików

    python -m py_compile -
    File1.py
    File2.py
    File3.py
       .
       .
       .
    
  2. Używając py_compile.compile:

    import py_compile
    py_compile.compile('YourFileName.py')
    
  3. Używając py_compile.main():

    Kompiluje jednocześnie kilka plików.

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

    Lista może rosnąć tak długo, jak chcesz. Alternatywnie możesz oczywiście przekazać listę plików w głównych lub nawet nazwach plików w argumentach wiersza poleceń.

    Lub, jeśli przekażesz ['-']main, może on interaktywnie kompilować pliki.

  4. Używając compileall.compile_dir():

    import compileall
    compileall.compile_dir(direname)
    

    Kompiluje każdy pojedynczy plik Pythona obecny w podanym katalogu.

  5. Używając compileall.compile_file():

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

Spójrz na poniższe linki:

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

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

Abhishek Kashyap
źródło
Jedną małą poprawką jest to, że nazwa ładowanego modułu to py_compilei compileallNIE py_compile.pylub compileall.py. Innymi słowy, powinno to być python3 -m py_compile PYTHON_FILENAMElub python3 -m compileall PYTHON_FILES_DIRECTORY.
Devy
18

Użyłbym compileall . Działa dobrze zarówno z poziomu skryptów, jak iz wiersza poleceń. Jest to moduł / narzędzie nieco wyższego poziomu niż wspomniany już py_compile , którego używa również wewnętrznie.

Pekka Klärck
źródło
compileallnie zawiera logiki do pomijania plików, dla których odpowiadający im .pycplik jest już aktualny, prawda?
Kyle Strand
2
@KyleStrand compileallpomija pliki, które są już aktualne .pyc(testowane z Pythonem 2.7.11)
tytułowy
@Eponymous Interesting. Nie wiem, dlaczego myślałem inaczej. Dzięki za sprawdzenie.
Kyle Strand
9

W Pythonie2 możesz użyć:

python -m compileall <pythonic-project-name>

który kompiluje wszystkie .pypliki do .pycplików w projekcie, który zawiera zarówno pakiety, jak i moduły.


W Pythonie3 możesz użyć:

python3 -m compileall <pythonic-project-name>

który kompiluje wszystkie .pypliki do __pycache__folderów w projekcie, który zawiera zarówno pakiety, jak i moduły.

Lub z brązowieniem z tego posta :

Możesz wymusić ten sam układ .pycplików w folderach, co w Python2, używając:

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

Opcja -bwyzwala wyjście .pycplików do ich starszych lokalizacji (tj. Takich samych jak w Pythonie2).

Benyamin Jafari
źródło
4

Aby dopasować oryginalne wymagania dotyczące pytania (ścieżka źródłowa i ścieżka docelowa), kod powinien wyglądać następująco:

import py_compile
py_compile.compile(py_filepath, pyc_filepath)

Jeśli kod wejściowy zawiera błędy, zgłaszany jest wyjątek py_compile.PyCompileError .

ababak
źródło
1

Można to zrobić na dwa sposoby

  1. Wiersz poleceń
  2. Korzystanie z programu w języku Python

Jeśli używasz wiersza poleceń, python -m compileall <argument>skompiluj kod Pythona do kodu binarnego Pythona. Dawny:python -m compileall -x ./*

Lub można użyć tego kodu do kompilacji biblioteki do kodu bajtowego.

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)

zajrzyj na ☞ docs.python.org, aby uzyskać szczegółową dokumentację

Prashant
źródło