Это называется "строка литерал интерполяция".Строка должна быть литералом, т.е. во время компиляции компилятор превратит строку в правильный исполняемый код.Если у вас уже есть строка в качестве значения (не как литерала), для этого уже слишком поздно.
У меня нет доступа к Python с включенным PEP 498, поэтому мои примеры будут на Ruby,который имел этот механизм в течение длительного времени.Синтаксис Ruby для f"...{expr}..."
в Python: "...#{expr}..."
.
. В Ruby "a#{2 * 3}b"
является синтаксическим сахаром для ["a", (2 * 3), "b"].join
(т. Е. Они производят точно такой же байт-код).Если у вас уже есть строка "2 * 3"
в качестве значения, компилятор ничего не может с этим поделать;единственный способ превратить строковое значение в результат - это оценить его.
В первом примере у вас есть строковый литерал внутри строкового литерала;оба обрабатываются компилятором во время компиляции: когда компилятор видит внешний литерал, он компилирует его, находит там другой строковый литерал, а также компилирует его, генерирует код.Фактически, "a#{"#{2 * 3}"}b"
производит точно такой же байт-код, опять же.
Тот факт, что это делается во время компиляции, также является причиной того, что интерполяция строкового литерала вызовет синтаксическую ошибку, если выражение внутриискажен, даже если рассматриваемая строка никогда не выполняется: if false; "#{1+}"; end
будет выдавать SyntaxError
.
Тот факт, что это делается во время компиляции, означает, что строки, уже находящиеся в переменных, не подходят для этого механизма.В вашем коде к моменту оценки res
, expr
могло бы быть чем угодно;единственный выход - evil
(или другой, более безопасный, оценщик).