В статье «Wicked Python Trickery» Эрик Ма делится необычным и мощным методом динамической модификации исходного кода функций во время выполнения программы.
Что за трюк?
В Python каждая функция имеет атрибут
.__code__, который представляет собой объект байткода. Используя функции compile() и exec(), можно создать новый исходный код функции, скомпилировать его в байткод и выполнить в нужном пространстве имён. Это позволяет заменить поведение функции без её явного переопределения:
def something():
raise NotImplementedError()
new_code = """
def something(x: int) -> int:
return x * 2
"""
compiled = compile(new_code, "<magic>", "exec")
ns = {}
exec(compiled, {}, ns)
something_new = ns["something"]
print(something_new(21)) # Выведет 42
Здесь мы создаём новый исходный код функции
something, компилируем его и выполняем в пустом пространстве имён. Затем извлекаем новую функцию из этого пространства и вызываем её.Практическое применение
Эрик использовал этот метод для создания бота, который выбирает инструменты для выполнения, но не выполняет их сам. Вместо этого он генерирует Python-функции на лету, которые имеют доступ ко всем глобальным переменным текущего сеанса. Это позволяет создавать гибкие и мощные инструменты без необходимости заранее определять все возможные функции.
Этот подход позволяет LLM (Large Language Model) генерировать код, который может использовать текущие данные и функции, доступные в глобальном пространстве имён.
Риски безопасности
Однако такой подход сопряжён с серьёзными рисками. Выполнение сгенерированного кода без должной проверки может привести к выполнению вредоносных действий, таких как удаление файлов, утечка данных или атаки на внешние сервисы. Эрик отметил, что в текущей реализации отсутствует защита от таких угроз, и планирует использовать инструменты, такие как Restricted Python, для ограничения возможностей выполняемого кода.
#факт
@zen_of_python