What you want is not possible with any built-in facility in Python shy of eval
; f-strings are a syntactic feature of the language itself, there is no built-in function or module that implements them in a way you can use aside from eval
. In CPython, when the compiler gets through with an f-string, there is nothing left of the original "string", it's been broken down into bytecode constructing the individual elements, followed by an instruction that puts them all together (omitted for simple cases where there is only one component being built). For example:
import dis
dis.dis("f'{a.bit_length()}{len(b)}'")
produces:
1 0 LOAD_NAME 0 (a)
2 LOAD_METHOD 1 (bit_length)
4 CALL_METHOD 0
6 FORMAT_VALUE 0
8 LOAD_NAME 2 (len)
10 LOAD_NAME 3 (b)
12 CALL_FUNCTION 1
14 FORMAT_VALUE 0
16 BUILD_STRING 2
18 RETURN_VALUE
Try it online!
(the _NAME
bytecodes might be _FAST
or _GLOBAL
or the like when running in functions, and the RETURN_VALUE
is an artifact of how dis
works with isolated expressions, but the general structure is the otherwise the same).
If you need essentially arbitrary code execution from provided template text (that's what f-strings are after all), you're stuck going with eval
or a third-party library with similar (not identical) functionality, e.g. Jinja2 and the like. In practice, I think you have an XY problem, but on the off chance you don't, you want third party full-featured templating.