Hi there,

is there an easy way to evaluate a string stored in a variable as if it were an f-string at runtime?

I.e., what I want is to be able to do this:

x = { "y": "z" }
print(f"-> {x['y']}")

This prints "-> z", as expected. But consider:

x = { "y": "z" }
s = "-> {x['y']}"
print(s.format(x = x))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: "'y'"

Even though

s = "-> {x}"
print(s.format(x = x))

Prints the expected "-> {'y': 'z'}".

This is supposedly for security reasons. However, when trying to emulate this behavior that I wanted (and know the security implications of), my solutions will tend to be less secure. Here is what I have been thinking about:

1. Somehow wrap "s" into an f-string, then eval. E.g.:

eval("f'" + s + "'")

This is a pain in the ass because you have to know what kind of quotation signs are used inside the expression. In the given case, this wouldn't work (but 'f"' prefix and '"' suffix would).

2. Parse the expression (regex?), then eval() the individual arguments, then run through format(). Pain in the ass to get the exact same behavior as f-strings. Probably by regex alone not even guaranteed to be parsable (especially corner cases with escaped '{' signs or ':' or '{' included inside the expression as a literal).

3. Somehow compile the bytecode representing an actual f-string expression, then execute it. Sounds like a royal pain in the butt, have not tried it.

All solutions are extremely undesirable and come with heavy drawbacks. Is there any standard solution (Py3.10+) that does what I would? Anything I'm missing?

Thanks,
Johannes
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to