← Назад к вопросам

Что такое PyC?

2.0 Middle🔥 121 комментариев
#Python Core#Soft Skills

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

PyC — Скомпилированный байткод Python

PyC (Python Compiled) — это формат файлов скомпилированного байткода Python с расширением .pyc. Они хранят промежуточное представление исходного кода Python, оптимизированное для выполнения виртуальной машиной CPython. PyC файлы — критический механизм для ускорения загрузки модулей и экономии ресурсов.

Как работает компиляция в PyC?

Когда Python интерпретатор импортирует модуль, он проходит несколько этапов:

  1. Парсинг — исходный код .py преобразуется в AST (Abstract Syntax Tree)
  2. Компиляция — AST компилируется в байткод (низкоуровневые инструкции для Python VM)
  3. Кэширование — байткод сохраняется в файл .pyc в директории __pycache__
  4. Выполнение — байткод выполняется CPython виртуальной машиной

На следующий раз при импорте сохранённый .pyc используется вместо повторной компиляции:

# mymodule.py
def calculate(x, y):
    return x + y

# main.py
import mymodule  # Первый импорт: парсинг + компиляция + сохранение в .pyc

mymodule.calculate(5, 3)

Структура PyC файла

PyC файл содержит заголовок и комплилированный байткод:

[Magic Number (4 байта)] [Timestamp (4 байта)] [File Size (4 байта)] [Bytecode]
  • Magic Number — идентификатор версии Python (различается для разных версий: 3.9, 3.10, 3.11 и т.д.)
  • Timestamp — время модификации исходного файла (для проверки кэша)
  • Bytecode — скомпилированный код

Анализ PyC файлов

import dis
import marshal

# Способ 1: Дизассемблирование с помощью dis
def greet(name):
    greeting = f"Hello, {name}!"
    print(greeting)

dis.dis(greet)

# Способ 2: Работа с PyC файлом напрямую
with open('__pycache__/mymodule.cpython-310.pyc', 'rb') as f:
    magic = f.read(4)  # Magic number
    flags = f.read(4)  # Флаги
    timestamp = f.read(4)  # Timestamp
    size = f.read(4)  # Размер исходного файла
    bytecode = marshal.load(f)  # Байткод
    print(f'Magic: {magic.hex()}')
    print(f'Bytecode: {bytecode}')

Когда PyC переносится?

PyC пересоздаётся, если:

  1. Исходный файл изменился — timestamp больше не совпадает
  2. Версия Python изменилась — magic number не совпадает
  3. Удалён .pyc — будет пересоздан при следующем импорте
  4. Изменилась переменная окруженияPYTHONDONTWRITEBYTECODE=1 запретит создание .pyc
# Запретить создание .pyc файлов
export PYTHONDONTWRITEBYTECODE=1

# Очистить все .pyc файлы
find . -type d -name __pycache__ -exec rm -rf {} +
find . -type f -name "*.pyc" -delete

# Компилировать модули заранее (для оптимизации)
python -m compileall mypackage/

Оптимизация с помощью PyC

# Вариант 1: Автоматическое кэширование (по умолчанию)
import sys
sys.dont_write_bytecode = False  # По умолчанию

# Вариант 2: Предварительная компиляция для production
import compileall

compileall.compile_dir(
    'mypackage',
    force=True,  # Пересоздать все .pyc
    quiet=1      # Не выводить логи
)

# Вариант 3: Использование py_compile для отдельных файлов
import py_compile

py_compile.compile('mymodule.py', cfile='__pycache__/mymodule.pyc')

PyC в production

В production окружении .pyc файлы имеют большое значение:

import sys
import py_compile
import os

def prepare_for_production(package_dir):
    # Компилируем весь пакет
    for root, dirs, files in os.walk(package_dir):
        for file in files:
            if file.endswith('.py'):
                filepath = os.path.join(root, file)
                try:
                    py_compile.compile(filepath, optimize=2)
                except py_compile.PyCompileError as e:
                    print(f'Failed to compile {filepath}: {e}')
    
    # Проверяем наличие .pyc
    pyc_count = sum(
        1 for root, dirs, files in os.walk(package_dir)
        for f in files if f.endswith('.pyc')
    )
    print(f'Compiled {pyc_count} modules')

prepare_for_production('myapp')

Уровни оптимизации PyC

# -O: базовая оптимизация (удаление assert, __debug__ блоков)
python -O myapp.py

# -OO: агрессивная оптимизация (удаление docstrings)
python -OO myapp.py

# Уровни сохраняются в расширении .pyc:
# mymodule.cpython-310.pyc         (без оптимизации)
# mymodule.cpython-310.opt-1.pyc   (с -O)
# mymodule.cpython-310.opt-2.pyc   (с -OO)

Проблемы с PyC

Проблема 1: Устаревший кэш

Если забыть очистить .pyc, старый код может выполняться. Всегда очищай кэш при обновлениях:

rm -rf __pycache__/

Проблема 2: Безопасность

.pyc файлы можно декомпилировать (uncompyle6, decompyle3). Не полагайся на .pyc как на защиту от обратного инжиниринга:

pip install uncompyle6
uncompyle6 __pycache__/mymodule.cpython-310.pyc > recovered.py

Проблема 3: Кроссплатформные различия

.pyc привязаны к версии Python, но не к операционной системе. Один .pyc может использоваться на Linux, Windows, macOS (если одна версия Python).

Проверка наличия PyC

import importlib.util

def is_cached(module_name):
    spec = importlib.util.find_spec(module_name)
    if spec and spec.cached:
        return True
    return False

print(is_cached('json'))  # True — встроенный модуль уже скомпилирован
print(is_cached('mymodule'))  # True/False в зависимости от кэша

Резюме: PyC файлы — это кэш скомпилированного байткода, который ускоряет загрузку модулей в Python. Хотя они создаются автоматически, понимание их природы помогает оптимизировать приложения и диагностировать проблемы с загрузкой модулей.

Что такое PyC? | PrepBro