Evaluation of variable as f-string

Rob Cliffe rob.cliffe at btinternet.com
Sat Jan 28 11:39:49 EST 2023


On 27/01/2023 23:41, Chris Angelico wrote:
> On Sat, 28 Jan 2023 at 10:08, Rob Cliffe via Python-list
> <python-list at python.org>  wrote:
>> Whoa! Whoa! Whoa!
>> I appreciate the points you are making, Chris, but I am a bit taken
>> aback by such forceful language.
> The exact same points have already been made, but not listened to.
> Sometimes, forceful language is required in order to get people to
> listen.
>
>> If it's addressed to me:  How about if I wanted a program (a learning
>> tool) to allow the user to play with f-strings?
>> I.e. to type in a string, and then see what the result would be if it
>> had been an f-string?
>> I suspect there are other use cases, but I confess I can't think of one
>> right now.
> Use the REPL, which will happily evaluate f-strings in their original
> context, just like any other code would. You're already eval'ing, so
> it's exactly what you'd expect. This is not the same thing as "typing
> in a string", though - it's typing in code and seeing what the result
> would be. (Except to the extent that source code can be considered a
> string.)
This is hypothetical, but I might want to work on a platform where the 
REPL was not available.
>
>> If it's addressed to me: "it" means a function that will take a string
>> and evaluate it at runtime as if it were an f-string.  Sure, with
>> caveats and limitations.
> And that's what I am saying is a terrible terrible idea. It will
> evaluate things in the wrong context, it has all the normal problems
> of eval, and then it introduces its own unique problems with quote
> characters.
With great respect, Chris, isn't it for the OP (or anyone else) to 
decide - having been warned of the various drawbacks and limitations - 
to decide if it's a terrible idea *for him*?  He's entitled to decide 
that it's just what *he* needs, and that the drawbacks don't matter *for 
him".  Just as you're entitled to disagree.
>
>>   And indeed Thomas Passim found this partial
>> solution on Stack Overflow:
>> def effify(non_f_str: str):
>>       return eval(f'f"""{non_f_str}"""')
> You can find anything on Stack Overflow. Just because you found it
> there doesn't mean it's any good - even if it's been massively
> upvoted.
>
>> Addressing your points specifically:
>>       1) I believe the quote character limitation could be overcome. It
>> would need a fair amount of work, for which I haven't (yet) the time or
>> inclination.
> No problem. Here, solve it for this string:
>
> eval_me = ' f"""{f\'\'\'{f"{f\'{1+2}\'}"}\'\'\'}""" '
>
> F-strings can be nested, remember.
I remember it well.
As far as I can see (and I may well be wrong; thinking about this 
example made my head hurt 😁) this could be solved if PEP 701 were 
implemented (so that f-string expressions can contain backslashes) but 
not otherwise.
>
>>       2) Yes in general you would have to pass it one dictionary, maybe
>> two.  I don't see this as an insuperable obstacle.  I am not sure what
>> you mean by "can't be done with full generality" and perhaps that's not
>> important.
>>>> def func():
> ...     x = 1
> ...     class cls:
> ...             y = 2
> ...             print(f"{x=} {y=}")
> ...             print(locals())
> ...
>>>> func()
> x=1 y=2
> {'__module__': '__main__', '__qualname__': 'func.<locals>.cls', 'y': 2}
Thanks for clarifying.
Hm.  So 'x' is neither in locals() nor in globals().  Which starts me 
wondering (to go off on a tangent): Should there be a nonlocals() 
dictionary?
>
> Maybe you don't care. Maybe you do. But locals() is not the same as
> "all names currently available in this scope". And, this example is
> definitely not something I would recommend, but good luck making this
> work with eval:
>
>>>> def func():
> ...     x = 1
> ...     print(f"{(x:=2)}")
> ...     print(x)
> ...
>>>> func()
> 2
> 2
> ...     x = 1
> ...     print(eval("(x:=2)", globals(), locals()))
> ...     print(x)
> ...
>>>> func()
> 2
> 1
Now that, I have to admit, IS a challenge!
>
>>       3) Not sure I understand this.
> Before f-strings existed, one of the big problems with "just use
> str.format_map" was that you can't just pass it locals() to get all
> the available names. You also can't eval arbitrary code and expect to
> get the same results, even if you pass it globals and locals. And
> various other considerations here - the exact issues seen here, but
> flipped on their heads. So the obvious question is: why not just use
> str.format_map?
>
What this underlines to me is what a good thing f-strings are.  And with 
PEP 701 they will be IMO even better.
Just as when you were working on PEP 463 (Exception-catching 
expressions) - which I still think would be a Good Thing - some research 
I did made me realise how good the existing try/except/else/finally 
mechanism actually is.  There's lots of Good Stuff in Python. 😁
Best wishes
Rob




More information about the Python-list mailing list