Полноценная защита от вскрытия - отдельная и большая задача. В большинстве случаев, к счастью, достаточно просто спрятать исходный код в надежде, что разбираться с ним будет просто лень. Из бинарных файлов для этого достаточно вырезать таблицу символов, а скрипты - обфусцировать, бессмысленно изменив имена переменных и внеся избыточную логику, или превратить их в бинарные файлы, следуя методу чайника. Для Python существуют даже онлайн-сервисы, выполняющие подобную работу.
И всё-таки в случае с Python можно обойтись без таких ухищрений, тем более, что восстановить исходные коды после подобных преобразований не столь сложно. При ближайшем рассмотрении Python, как и многие другие интерпретируемые языки, перед исполнением скрипта компилирует его в байт-код, который уже исполняется виртуальной машиной интерпретатора. После запуска любого проекта, написанного на Python, в рабочей директории создаётся директория
__pycache__/, содержащая .pyc -файлы - скомпилированные представления каждого из модулей:$ ls -1
main.py
utils.py
$ cat *
# main.py
import utils
print(utils.hi)
# utils.py
hi = 'hi'
$ python3 main.py
hi
$ ls -R1
.:
__pycache__
main.py
utils.py
./__pycache__:
utils.cpython-312.pyc
За компиляцию отвечают встроенные модули Python py_compile и compileall, которые можно вызвать явно, что мы и сделаем, чтобы скомпилировать файл
main.py:$ python3 -m py_compile main.py
$ ls -1 __pycache__
main.cpython-312.pyc
utils.cpython-312.pyc
Это представление уже достаточно надёжно "прячет" код от пользователя, а главное, его можно использовать и в отсутствие файлов с исходным кодом, что в значительной мере решает поставленную задачу:
# Remove source code
$ rm *.py
# Place .pyc-files in place of .py
$ mv __pycache__/* .
$ rm -rf __pycache__; ls -1
main.cpython-312.pyc
utils.cpython-312.pyc
# Run!
$ python3 main.cpython-312.pyc
hi
Решение, прибегающее к "sourceless Python", всегда будет требовать той же версии Python, для которой был сгенерирован байт-код: промежуточное представление кода часто меняется, и Python3.12 почти наверное не сможет прочитать
.pyc -файл версии 3.11. В прочем, если код поставляется в виде docker-образа, то согласовать версию интерпретатора с байт-кодом будет не так сложно.Пользователь также может попытаться восстановить исходный код с помощью декомпилятора, например, decompyle, но угнаться за стандартом не так-то просто - байт-код для версий свежее, чем 3.8, восстановить на момент написания заметки скорее всего pycache
$ decompyle3 __pycache__/utils.cpython-312.pyc
...
Unsupported Python version, 3.12.0, for decompilation
...


