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.
'{}'.format(s[:4])?..[:4]. Especially if it's outsourced for translation or something. What you propose also violates the basic programming/design principle of separation of concerns. Putting the string together is a separate task from determining the values for interpolation.eval, for all practical purposes (in the bytecode, they're built piecemeal by evaluating their components and putting them all together). If you want to doevaly things withstr.format,evalwill be involved. This specific case could be handled with'{!s:.4}'.formatif the argument will be astror you want the first four characters of its stringified form (the!scan be omitted if it's always astr), but you can't use slicing syntax, it's that simple.eval. f-strings are a syntactic feature of the language; they're baked into the Python parser/bytecode compiler itself. In the compiled bytecode, there isn't an f-string at all (see the disassembly here). I assumed you were looking for a general solution (thus the emphasis on specific); the answer is to use some other templating library with similar features (e.g. Jinja2).