Как скомпилировать python файл в pyc
Перейти к содержимому

Как скомпилировать python файл в pyc

  • автор:

Python — возможно ли скомпилировать *.py в *.pyc, при отсутствии некоторых нужных модулей, чтобы компилятор «закрыл на это глаза»?

Зачем нужен этот изврат:
чтобы вносить изменения в приложение, не пересобирая его целиком из исходного кода, а то и вообще не имея такового. И также не декомпилируя его полностью (там целая куча этих *.pyc, а изменить нужно лишь 1).

Отслеживать
задан 6 дек 2017 в 5:49
SimAlllllll SimAlllllll
31 5 5 бронзовых знаков
Связанный вопрос: Компиляция на Python кода Python
6 дек 2017 в 8:18
@andreymal И причем здесь eval?
6 дек 2017 в 8:29
Посмотрите внимательнее, там не только про eval
6 дек 2017 в 9:33
cвязанный вопрос Компиляция на Python кода Python
7 дек 2017 в 8:16

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

чтобы компилятор «закрыл на это глаза»

Компилятор не делает никаких проверок кода, кроме синтаксических. Все ошибки импорта, несуществующих переменных и прочей такой дребедени происходят уже во время интерпретации заранее скомпилированного байткода.

А для компиляции байткода без его последующего запуска можно использовать модуль py_compile :

python -m py_compile yourfile.py 

В Python 2 будет создан yourfile.pyc , в Python 3 будет создан __pycache__/yourfile.cpython-3N.pyc .

Также есть compileall , который умеет компилировать не только отдельные файлы, но и всё содержимое указанных каталогов рекурсивно:

python -m compileall путь-к-каталогу-с-модулями/ 

Как скомпилировать python файл в pyc

При выполнении скрипта на языке Python все выполнение в общем случае разбивается на две стадии:

  1. Файл с кодом (файл с расширением .py ) компилируется в промежуточный байткод.
  2. Далее скомпилированный байткодом интерпретируется, то есть происходит собственно выполнение программы

При этом нам не надо явным образом генерировать никакой байткод, он создается неявно при выполнении скрипта Python. Если программа импортирует внешние модули/библиотеки и они импортируются первый раз, то их скомпилированный байткод сохраняется сохраняется в файле с расширением .pyc и кэшируется в каталоге __pycache__ в папке, где расположен файл с кодом python. Если мы вносим в исходный файл библиотеки изменения, то Python перекомпилирует файл байткода. Если изменений в коде нет, то загружается ранее скомпилированный байткод из файла *.pyc . Это позволяет оптимизировать работу с приложением, быстрее его компилировать и выполнять.

Однако байткод основного скрипта, который представляет основной файл программы и который передается интерпретатору python, не сохраняется в файле *.pyc и перекомпилируется каждый раз при запуске приложения.

Допустим, в папке проекта у нас размещен файл user.py со простейшей функцией, которая принимает два параметра и выводит их значения:

def printUser(username, userage): print(f"Name: Age:")

Подключим этот файл в главном модуле программы, который пусть называется app.py :

import user username = "Tom" userage = 39 user.printUser(username, userage)

При выполнении этого скрипта в папке проекте (где располагается модуль «user.py») будет создан каталог __pycache__ . А в нем будет сгенерирован файл байткода, который будет наподобие следующего user.cpython-версия.pyc , где в качестве версии будет применяться версия используемого интерпретатора, например, 311 (для версии Python 3.11). Сгенерированный pyc -файл является бинарным, поэтому текстовом редакторе нет смысла его открывать.

__pycache__ и модули в языке программирования Python

Ручная компиляция байткода

Хотя файл байткода создается автоматически, мы вручную можем его сгенерировать. Для этого есть несколько способов: компиляция с помощью скрипта py_compile и компиляция с помощью модуля compileall .

Скрипт py_compile применяется для компиляции отдельных файлов. Для компиляции произвольного скрипта user.py в файл с байткодом мы могли бы использовать следующую программу:

import py_compile py_compile.compile("user.py") # передаем путь к скрипту

Для компиляции в функцию compile() передаем путь к скрипту. После выполнения программы в текущей папке также будет сгенерирован каталог __pycache__ , а в нем файл user.cpython-311.pyc

Модуль compileall применяется для компиляции всех файлов Python по определенным путям. Например, скомпилируем все файлы в каталоге C:/python/files

python -m compileall c:\python\files

По умолчанию компилируются даже те файлы, которые содержатся в подкаталогах. Если надо скомпилировать только те файлы, которые располагаются непосредственно в указанно папке, то применяется опция -l

python -m compileall c:\python\files -l

py_compile — Компиляция исходных файлов Python¶

Модуль py_compile предоставляет функцию для генерации файла байт-кода из исходного файла и другую используемую функцию, когда исходный файл модуля вызывается в качестве сценария.

Хотя он не часто необходим, он может быть полезен, устанавливая модули для общего использования, особенно если у некоторых пользователей может не быть разрешения написать байту-код файлы кэш в справочнике, содержащем исходный код.

exception py_compile. PyCompileError ¶

Исключение при возникновении ошибки при попытке компиляции файла.

py_compile. compile ( file, cfile=None, dfile=None, doraise=False, optimize=-1, invalidation_mode=PycInvalidationMode.TIMESTAMP, quiet=0 ) ¶

Скомпилировать исходный файл в байт-код и записать файл кэша байт-кода. Исходный код загружается из файла с именем file. Байт-код записывается в cfile, который по умолчанию соответствует пути PEP 3147 / PEP 488, оканчивающемуся на .pyc . Например, если file — это /foo/bar/baz.py , cfile по умолчанию будет /foo/bar/__pycache__/baz.cpython-32.pyc для Python 3.2. Если указано dfile, оно используется как имя исходного файла в сообщениях об ошибках вместо file. Если doraise истинно, PyCompileError возникает при обнаружении ошибки при компиляции file. Если doraise имеет значение false (по умолчанию), строка ошибки записывается в sys.stderr , но исключение не возникает. Эта функция возвращает путь к файлу с байтовой компиляцией, т.е. какое бы значение cfile ни использовалось.

Аргументы doraise и quiet определяют способ обработки ошибок при компиляции файла. Если quiet равно 0 или 1, а doraise равно false, то включается поведение по умолчанию: ошибка строка записывается в sys.stderr , а функция возвращает None вместо пути. Если doraise имеет значение true, вместо него возникает PyCompileError . Однако, если quiet равно 2, сообщение не записывается, и doraise не имеет эффекта.

Если путь, которым становится cfile (или явно определенный или вычисленный) будет симлинк или необычный файл, то будет поднято FileExistsError . Это должно быть предупреждением, что импорт превратит эти пути в обычные файлы, если разрешено записывать скомпилированные байтами файлы в эти пути. Это побочный эффект импорта с использованием переименования файлов, чтобы поместить на место последний скомпилированный в байтах файл, чтобы предотвратить одновременные проблемы записи файлов.

optimize управляет уровнем оптимизации и передается встроенной функции compile() . По умолчанию для параметра -1 выбирается уровень оптимизации текущего интерпретатора.

invalidation_mode должен быть членом перечисления PycInvalidationMode и управляет тем, как сгенерированный байт-код кэш считается недействительным во время выполнения. Значение по умолчанию равно PycInvalidationMode.CHECKED_HASH , если установлена переменная среды SOURCE_DATE_EPOCH , в противном случае значение по умолчанию равно PycInvalidationMode.TIMESTAMP .

Изменено в версии 3.2: Измененный по умолчанию значение cfile, чтобы быть PEP 3147-соответствующим. Предыдущее значение по умолчанию: file + ‘c’ ( ‘o’ если была включена оптимизация). Также добавлен параметр optimize.

Изменено в версии 3.4: Изменено код для использования importlib для записи файла байт-код кэш. Это означает, что семантика создания/записи файлов теперь соответствует тому, что делает importlib , например, разрешения, семантика записи и перемещения и т.д. Также добавлена оговорка, что FileExistsError возникает, если cfile является symlink или нерегулярным файлом.

Изменено в версии 3.7: Параметр invalidation_mode добавлен, как указано в разделе PEP 552. Если переменная окружения SOURCE_DATE_EPOCH будет установлена, то invalidation_mode будет вызван к PycInvalidationMode.CHECKED_HASH .

Изменено в версии 3.7.2: Переменная окружения SOURCE_DATE_EPOCH больше не отвергает значение аргумента invalidation_mode и определяет его по умолчанию значение вместо этого.

Изменено в версии 3.8: Добавлен параметр quiet.

class py_compile. PycInvalidationMode ¶

Перечисление возможных методов, которые интерпретатор может использовать для определения того, является ли файл байт-кода актуальным для исходного файла. Файл .pyc указывает требуемый режим недействительности в заголовке. Дополнительные сведения о том, как Инвалидация кэша байткода делает файлы Python недействительными во время выполнения, см. в разделе .pyc .

Добавлено в версии 3.7.

Файл .pyc включает метку времени и размер исходного файла, который Python сравнит с метаданными исходного файла во времени выполнения, чтобы определить, должен ли файл .pyc быть восстановлен.

Файл .pyc включает мешанину содержания исходного файла, которое Python сравнит с источником во времени выполнения, чтобы определить, должен ли файл .pyc быть восстановлен.

Как и CHECKED_HASH , файл .pyc включает в себя хэш содержимого исходного файла. Однако во время выполнения программы Python будет предполагать, что файл .pyc обновлен и вообще не проверяет .pyc на соответствие исходному файлу.

Этот выбор полезен, когда .pycs усовершенствованы некоторой системой, внешней к Python как построить система.

py_compile. main ( args=None ) ¶

Скомпилировать несколько исходных файлов. Файлы назвали в args (или на командной строке, если args — None ), собраны, и получающийся байт-код припрятался про запас нормальным способом. Эта функция не выполняет поиск исходных файлов в структуре каталогов; он компилирует только файлы, именованные явно. Если ‘-‘ является единственным параметром в args, список файлов берется из стандартного ввода.

Изменено в версии 3.2: Добавлена поддержка ‘-‘ .

Когда этим модулем управляют как сценарий, main() — используемый, чтобы собрать все файлы, названные на командной строке. Состояние выхода ненулевое, если один из файлов не удалось скомпилировать.

Модуль compileall Утилиты для компиляции всех исходных файлов Python в дереве каталогов.

Гайд Как скомпилить и задекомпилить .pyc файл в Python

Для компиляции .py файлов в .pyc файлы в Python можно использовать встроенный модуль py_compile. Для этого необходимо выполнить следующий код в терминале:

python -m py_compile script.py

После этого в той же директории, где находится исходный файл script.py, будет создан скомпилированный файл script.pyc.

Декомпиляция .pyc файлов в .py файлы

Для декомпиляции .pyc файлов в .py файлы в Python можно использовать модуль uncompyle6. Для установки модуля можно воспользоваться менеджером пакетов pip следующим образом:

pip install uncompyle6

После установки модуля можно выполнить следующий код в терминале, чтобы декомпилировать скомпилированный файл script.pyc:

uncompyle6 script.pyc > script.py

После этого в той же директории, где находится скомпилированный файл script.pyc, будет создан исходный файл script.py.

Теперь вы знаете, как скомпилировать и задекомпилировать .pyc файлы в Python. Это может быть полезным, например, при отладке или изучении чужого кода.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *