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

Что такое уровни логирования?

2.0 Middle🔥 161 комментариев
#Асинхронность и многопоточность#Базы данных (SQL)

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

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

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

Файл .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, созданная для скорости, которую большинство разработчиков никогда не видят, но которая работает за сценой.

Что такое уровни логирования? | PrepBro