'How do I convert a string into an f-string?

I was reading this blog post on Python's new f-strings and they seem really neat. However, I want to be able to load an f-string from a string or file.

I can't seem to find any string method or other function that does this.

From the example in the blog post:

name = 'Fred'
age = 42
f"My name is {name} and I am {age} years old"

'My name is Fred and I am 42 years old'

But what if I had a string s? I want to be able to eff-ify s, something like this:

name = 'Fred'
age = 42
s = "My name is {name} and I am {age} years old"
effify(s)

It turns out I can already perform something similar to str.format and garner the performance pick up. Namely:

format = lambda name, age: f"My name is {name} and I am {age} years old"
format('Ted', 12)

'My name is Ted and I am 12 years old'


Solution 1:[1]

f-strings are code. Not just in the safe, "of course a string literal is code" way, but in the dangerous, arbitrary-code-execution way. This is a valid f-string:

f"{__import__('os').system('install ransomware or something')}"

and it will execute arbitrary shell commands when evaluated.

You're asking how to take a string loaded from a text file and evaluate it as code, and the answer boils down to eval. This is of course a security risk and probably a bad idea, so I recommend not trying to load f-strings from files.

If you want to load the f-string f"My name is {name} and I am {age} years old" from a file, then actually put

f"My name is {name} and I am {age} years old"

in the file, f and quotation marks and all.

Read it from the file, compile it and save it (so eval doesn't have to recompile it every time):

compiled_fstring = compile(fstring_from_file, '<fstring_from_file>', 'eval')

and evaluate it with eval:

formatted_output = eval(compiled_fstring)

If you do this, be very careful about the sources you load your f-strings from.

Solution 2:[2]

A simple solution would be to use f-strings and eval.

def effify(non_f_str: str):
    return eval(f'f"""{non_f_str}"""')

name = 'Fred'
age = 42
s = "My name is {name} and I am {age} years old"
effify(s)
'My name is Fred and I am 42 years old'

This basically prepends an "f" to the string and then evaluates as code. The triple quotes help to accommodate multiline strings as well. The function will try to pull the variables referenced in the f-string from the scope around its call. As pointed out, using eval can potentially be dangerous, but if you know your source, then I think it is not more dangerous than executing any other code.

Solution 3:[3]

But what if I had a string s? I want to be able to eff-ify s, something like this:

name = 'Fred'
age = 42
s = "My name is {name} and I am {age} years old"
effify(s)

AFAIU, According to PEP 498 -- Literal String Interpolation, this isn't possible1. There's no way to programmatically create an f-string:

In Python source code, an f-string is a literal string, prefixed with 'f', which contains expressions inside braces.


1Unless of course, you'd be willing to use something like exec as @coldspeed mentioned. But at that point, the cons probably outweigh the pros.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Peter Mortensen
Solution 3 Community