0

This is NOT a duplicate question, please read fully :

With python f-strings one can write :

s='abcdef'
f'{s[:4]}'
Out[17]: 'abcd'

But the actual str.format() function is not totally compatible with f-string syntax :

'{s[:4]}'.format(s=s)

Traceback (most recent call last):
  ...      
TypeError: string indices must be integers

There are some questions on S.O. speaking about that but all propose to use eval() which is not a good solution for security reasons : Is there a function somewhere I could call on a string so it can be interpreted as a f-string ?

16
  • 6
    Do you mean '{}'.format(s[:4])?.. Commented Jan 4, 2021 at 11:45
  • 2
    I guarantee you from professional experience with i18n/l10n, no, you would not like any such thing. If a programmer is writing the text file, the programmer will wonder why the code is not in a .py file; if a UI designer is writing it, that is a person who is not being paid to understand arcane nonsense like [: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. Commented Jan 4, 2021 at 11:57
  • 1
    @Eric I still don't understand. Just because you think a thing should exist, doesn't mean that it does exist. Should and consistency are nice, but programming languages violate those all the time. Since f-string is strictly speaking greatly more capable than the string format minilanguage there are going to be lots of f-strings you cannot express in the less capable DSL. So since the thing you want doesn't exist, what are you expecting to accomplish here? Commented Jan 4, 2021 at 12:14
  • 2
    @Eric: f-strings are a special-case of 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 do evaly things with str.format, eval will be involved. This specific case could be handled with '{!s:.4}'.format if the argument will be a str or you want the first four characters of its stringified form (the !s can be omitted if it's always a str), but you can't use slicing syntax, it's that simple. Commented Jan 4, 2021 at 12:16
  • 1
    @Eric: "I was expecting someone saying there is may be an offical or internal function for that." Yup, that's called 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). Commented Jan 4, 2021 at 13:09

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the explaination : you shown me it is really built-in, that's the reason why f-string is so fast. I was expecting to use it as a better template engine than .format() without using eval or another template engine... But I was also expecting to use f-formating in some python code places where I used to use str.format()... but I am sad it is not possible : it could be usefull, instead, I have to build a small function...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.