Модуль dis Python: аудит повторяющихся инструкций LOADGLOBAL

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Профилирование Python: задачи на cProfile, pstats и байт-код dis.

Аудит повторяющихся глобальных обращений

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

Если одно и то же имя запрашивается через глобальный доступ строго больше одного раза на протяжении тела функции, оно признаётся неоптимизированным кандидатом для локализации — кэширования в локальную переменную. Обращения, встречающиеся ровно один раз, считаются допустимыми и в отчёт не попадают.

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

Что уже дано

В редакторе импортирован модуль dis и подготовлена заготовка функции repeated_globals. В тестовом окружении также доступны вспомогательные функции make_global_audit_target(source) и observe_global_audit_target(target), но реализовывать их заново не требуется.

Что нужно сделать

Реализуйте функцию repeated_globals(func) -> list[str].

Функция принимает обычную функцию CPython func (включая функции с замыканиями, ветвлениями, циклами или вложенными определениями) и возвращает отсортированный по алфавиту (в лексикографическом порядке возрастания) список уникальных строк — имён, для которых в собственном потоке инструкций func встречается строго больше одной статической инструкции LOAD_GLOBAL.

Правила проверки:

  • Анализ выполняется статически по реальному байт-коду: вызывать саму функцию func запрещено.
  • Учитываются только статические места инструкций в кодовом объекте самой функции, а не число итераций во время выполнения (одна инструкция LOAD_GLOBAL внутри цикла считается ровно за одно вхождение).
  • Встроенные функции и константы (builtins), загружаемые через LOAD_GLOBAL, учитываются по тем же правилам, что и пользовательские глобальные переменные.
  • Используйте разрешённое строковое имя переменной (argval), а не форматированное строковое представление (argrepr), которое в Python 3.12 может содержать префиксы вроде NULL +.
  • Все остальные опкоды (например, LOAD_FAST, LOAD_ATTR, LOAD_DEREF) полностью игнорируются.
  • Не углубляйтесь рекурсивно во вложенные функции или генераторные выражения: проверяется только собственный поток инструкций переданной функции.
  • Если подходящих повторяющихся имён нет, функция должна вернуть пустой список [].

Ограничения:

  • количество инструкций в исследуемой функции не превышает 10 000;
  • длина имени глобальной переменной не превышает 100 символов.

Обратите внимание: это эвристический статический аудит байт-кода, а не измерение времени исполнения или гарантия ускорения.

Ввод и вывод

Стандартные потоки stdin и stdout не используются: считывать ввод и вызывать print() не нужно. Проверяющая система выполняет код решения и получает функцию верхнего уровня repeated_globals напрямую из состояния скрипта.

Пример использования

def kernel(x):
    return scale(x) + scale(x) + offset

print(repeated_globals(kernel))

Вывод:

['scale']
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи