Что такое уровни логирования?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Файл .pyc — скомпилированный Python код
Файл .pyc — это скомпилированный (но не исполняемый) Python код в виде байт-кода (bytecode). Он создаётся и используется интерпретатором Python для ускорения загрузки модулей и сохранения повторной компиляции.
Как появляются .pyc файлы
Оригинальный файл (script.py):
↓
Проверка интерпретатора: есть ли свежий .pyc?
↓ (Нет или устарел)
Компиляция .py → .pyc (в памяти + на диск)
↓
Исполнение байт-кода Python Virtual Machine (PVM)
Где хранятся .pyc файлы
Стандартная иерархия:
project/
├── my_module.py # Исходный код
└── __pycache__/
└── my_module.cpython-311.pyc # Скомпилированный код
Папка __pycache__:
- Создаётся автоматически при первом импорте модуля
- Содержит .pyc файлы для всех импортированных модулей
- Имя:
module_name.cpython-311.pyc(311 = Python 3.11) - Безопасно удалять — пересоздастся автоматически
# Посмотреть содержимое
ls -la project/__pycache__/
# my_module.cpython-311.pyc
# another_module.cpython-311.pyc
# Удалить (будут пересоздины)
rm -rf project/__pycache__
Структура .pyc файла
# Структура .pyc (бинарный формат):
┌─────────────────────────────────┐
│ Magic number (4 байта) │ Идентификатор версии Python
│ Timestamp или hash (8 байт) │ Для проверки: актуален ли файл?
│ Code object (основная часть) │ Скомпилированный байт-код
└─────────────────────────────────┘
Magic number — уникален для каждой версии Python:
import sys
import importlib.util
# Посмотреть magic number текущей версии
magic_number = importlib.util.cache_from_source.__code__.co_lnotab
print(f"Python {sys.version_info.major}.{sys.version_info.minor}")
# Или через modulo
print(sys.version_info)
Как Python использует .pyc файлы
1. При импорте модуля
# main.py
import my_module # Первый раз
print(my_module.greet())
# my_module.py
def greet():
return "Hello"
Процесс:
1. Python ищет my_module.py
2. Компилирует в байт-код
3. Сохраняет в __pycache__/my_module.cpython-311.pyc
4. Загружает и выполняет байт-код
Второй импорт:
1. Проверяет: есть ли мой_module.pyc и свежий ли он?
2. Если свежий → загружает .pyc напрямую (БЕЗ переколяции)
3. Если устарел → перекомпилирует
2. Проверка актуальности .pyc
Пython сравнивает timestamp (или hash) .py и .pyc:
import os
import marshal
# Простейшее сравнение
py_path = 'my_module.py'
pyc_path = '__pycache__/my_module.cpython-311.pyc'
py_time = os.path.getmtime(py_path)
pyc_time = os.path.getmtime(pyc_path)
if pyc_time < py_time:
print(".pyc устарел, нужна перекомпиляция")
else:
print(".pyc актуален, можно использовать")
Что на самом деле хранится в .pyc
# Пример: простая функция
def add(a, b):
return a + b
В .pyc хранится код-объект (code object):
import dis
import marshal
# Посмотреть байт-код функции
def add(a, b):
return a + b
dis.dis(add)
Вывод:
2 0 LOAD_FAST 0 (a)
2 LOAD_FAST 1 (b)
4 BINARY_ADD
6 RETURN_VALUE
Это байт-код — промежуточный код, которым оперирует Python Virtual Machine (PVM).
Преимущества .pyc файлов
1. Ускорение загрузки
# Без .pyc: компилирует каждый раз (медленно)
# С .pyc: загружает готовый код (быстро)
# Тест скорости
import time
start = time.time()
import large_module
end = time.time()
print(f"Первый импорт: {end - start:.4f}с") # Медленно
print(f"Второй импорт: быстро (из .pyc)")
2. Не требует исходного кода
Можно распространять только .pyc файлы (сырой вариант защиты):
# Скомпилировать все .py в .pyc
python -m py_compile my_module.py
# Использовать
python -c "import my_module; my_module.greet()"
# Сработает, даже если удалить my_module.py
3. Экономия памяти
Байт-код обычно меньше исходного текста (нет комментариев, пробелов).
Недостатки и проблемы
1. Проблемы при распределённом тестировании
# Кэшированные .pyc могут вызвать странные ошибки
# Решение: очищать перед тестами
rm -rf **/__pycache__
pytest tests/
2. Различные версии Python
project/__pycache__/
├── module.cpython-39.pyc # Python 3.9
├── module.cpython-310.pyc # Python 3.10
└── module.cpython-311.pyc # Python 3.11
Каждая версия Python создаёт свой .pyc! Несовместимы друг с другом.
# Если переключиться с Python 3.10 на 3.11
python3.11 script.py
# Создаст новый .pyc для 3.11, но старый 3.10 останется
Управление .pyc файлами
Отключить создание .pyc
# Флаг -B отключает создание/использование .pyc
python -B script.py
# Или через переменную окружения
PYTHONDONTWRITEBYTECODE=1 python script.py
Явная компиляция
import py_compile
# Скомпилировать один файл
py_compile.compile('my_module.py', cfile='my_module.pyc')
# Компилировать папку рекурсивно
import compileall
compileall.compile_dir('src/', quiet=1)
Очистка в проектах
# В .gitignore (НЕ коммитить .pyc)
__pycache__/
*.pyc
*.pyo
*.egg-info/
# Скрипт очистки
find . -type d -name __pycache__ -exec rm -r {} +
find . -type f -name '*.pyc' -delete
.pyc vs другие форматы
| Формат | Что это | Для чего | Скорость |
|---|---|---|---|
| .py | Исходный код | Разработка | Медленно (компилировать нужно) |
| .pyc | Байт-код | Оптимизация загрузки | Быстро (готов к исполнению) |
| .pyo | Оптимизированный .pyc | Старое (Python 2), больше не используется | - |
| .pyd/.so | Скомпилированные расширения | Высокая производительность | Очень быстро (машинный код) |
Практические советы
- Добавляй
__pycache__/в.gitignore— не коммитить на GitHub - Используй
PYTHONDONTWRITEBYTECODE=1в Docker (экономит место) - Очищай кэш перед CI/CD тестами — избежи "магических" ошибок
- Не пытайся редактировать .pyc — это бинарный формат, используй .py
- В production можно распространять .pyc — вместо источников (рудиментарная защита)
.pyc файлы — это оптимизация Python, созданная для скорости, которую большинство разработчиков никогда не видят, но которая работает за сценой.