Если аргумент фабрики декоратора зависит от текущего состояния программы, когда это состояние фиксируется относительно вызовов декорированной функции?
Аргументы фабрики декоратора вычисляются при выполнении определения функции, а не при каждом вызове декорированной функции. Затем вызывается фабрика, её результат применяется к функции, и полученный объект связывается с именем функции.
Важно различать зафиксированное значение и ссылку на изменяемый объект: если аргументом был список или словарь, декоратор может позднее увидеть изменения этого объекта.
Декораторы появились как способ декларативно расширять или заменять функции и методы без изменения их основного тела. Такой механизм особенно полезен для журналирования, проверки доступа, кеширования и измерения времени выполнения.
Фабрика декоратора добавляет ещё один уровень настройки: сначала создаётся декоратор с заданными параметрами, затем он применяется к функции. Это позволяет отделить конфигурацию поведения от выполнения самой функции.
Ошибочное предположение состоит в том, что фабрика декоратора выполняется при каждом вызове функции. На практике это привело бы к повторному созданию обёртки, повторной проверке конфигурации и возможному накоплению побочных эффектов.
Если конфигурация меняется после определения функции, результат зависит от её типа. Простое значение обычно уже передано фабрике, а изменяемый объект передан по ссылке и может быть изменён позднее. Непонимание этого различия вызывает трудноуловимые ошибки в настройках, логировании и контроле доступа.
Когда интерпретатор выполняет определение функции с декоратором-фабрикой, он сначала вычисляет выражения аргументов фабрики. После этого вызывается фабрика, полученный декоратор применяется к созданной функции, и итоговый объект сохраняется под исходным именем.
При обычном вызове функции эти этапы не повторяются. Вызывается уже сохранённый результат декорирования — чаще всего функция-обёртка или вызываемый объект.
В примере сообщение factory True выводится во время определения work, ещё до её вызова. При вызове work обёртка обращается к тому же словарю, поэтому после изменения settings["enabled"] условие уже ложно.
Если требуется зафиксировать конфигурацию независимо от дальнейших изменений объекта, нужно сделать копию или извлечь из объекта неизменяемое значение внутри фабрики. Это компромисс: копирование повышает предсказуемость, но может быть дорогим или неполным для сложных вложенных структур.
В сервисе декоратор ограничивает частоту запросов, а его параметр берётся из общего словаря конфигурации. Разработчик ожидает, что изменение конфигурации автоматически изменит лимит, но фабрика уже отработала при импорте модуля.
Вариант с созданием новой обёртки при каждом вызове неудачен: он увеличивает накладные расходы и может сбросить состояние счётчиков. Вариант с хранением ссылки на изменяемую конфигурацию позволяет применять изменения динамически, но требует потокобезопасности и ясного контракта.
Практичный выбор зависит от требований. Для динамических настроек обёртка может читать потокобезопасный объект конфигурации при вызове; для неизменяемой политики лучше скопировать нужные параметры при создании декоратора. Это делает поведение предсказуемым и не связывает каждый вызов с полной структурой конфигурации.
Нет. Фабрика выполняется при обработке определения функции, после чего её результат используется как декоратор. При последующих вызовах работает уже созданная обёртка.
Python передаёт в фабрику ссылку на объект, а не его автоматическую копию. Если обёртка или замыкание сохраняет эту ссылку, чтение списка или словаря позднее увидит его текущее содержимое. Для снимка состояния нужна явная копия либо извлечение неизменяемых значений.
Побочный эффект произойдёт в момент выполнения определения функции, часто во время импорта модуля. Он не будет повторяться при обычных вызовах функции. Поэтому такие выражения могут замедлять импорт, менять порядок инициализации или вызывать ошибки ещё до первого обращения к декорированной функции.