• Re: Evaluation of variable as f-string

    From Stefan Ram@21:1/5 to Johannes Bauer on Mon Jan 23 16:43:33 2023
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))

    x = { "y": "z" }
    def s( x ): return '-> ' + x[ 'y' ]
    print( s( x = x ))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Stefan Ram on Mon Jan 23 16:52:11 2023
    ram@zedat.fu-berlin.de (Stefan Ram) writes:
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))
    x = { "y": "z" }
    def s( x ): return '-> ' + x[ 'y' ]
    print( s( x = x ))

    One can use an f-string just as well in the function.

    import dis

    x = { "y": "z" }

    def s( x ): return '-> ' + x[ 'y' ]
    dis.dis( s )
    print( s( x = x ), end='\n\n' )

    def s( x ): return f"-> {x['y']}"
    dis.dis( s )
    print( s( x = x ))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Mon Jan 23 17:24:15 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Johannes Bauer on Tue Jan 24 05:02:56 2023
    On Tue, 24 Jan 2023 at 04:56, Johannes Bauer <dfnsonfsduifb@gmx.de> wrote:

    Hi there,

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

    ...

    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:

    If you really want the full power of an f-string, then you're asking
    for the full power of eval(), and that means all the security
    implications thereof, not to mention the difficulties of namespacing.
    Have you considered using the vanilla format() method instead?

    But if you really REALLY know what you're doing, just use eval()
    directly. I don't really see what you'd gain from an f-string. At very
    least, work with a well-defined namespace and eval whatever you need
    in that context.

    Maybe, rather than asking for a way to treat a string as code, ask for
    what you ACTUALLY need, and we can help?

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Antoon Pardon@21:1/5 to All on Wed Jan 25 19:26:47 2023
    Op 23/01/2023 om 17:24 schreef Johannes Bauer:
    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'}".

    I am probably missing something but is there a reason why the following wouldn't do what you want:

    x = { "y": "z" }
    s = "-> {target}"
    print(s.format(target = x['y']))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Antoon Pardon on Wed Jan 25 14:38:38 2023
    On 1/25/2023 1:26 PM, Antoon Pardon wrote:
    Op 23/01/2023 om 17:24 schreef Johannes Bauer:
    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'}".

    I am probably missing something but is there a reason why the following wouldn't do what you want:

    x = { "y": "z" }
    s = "-> {target}"
    print(s.format(target = x['y']))

    Stack overflow to the rescue:

    Search phrase: "python evaluate string as fstring"

    https://stackoverflow.com/questions/47339121/how-do-i-convert-a-string-into-an-f-string

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

    print(effify(s)) # prints as expected: "-> z"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Thomas Passin on Thu Jan 26 00:58:12 2023
    On 25/01/2023 19:38, Thomas Passin wrote:

    Stack overflow to the rescue:

    Search phrase:  "python evaluate string as fstring"

    https://stackoverflow.com/questions/47339121/how-do-i-convert-a-string-into-an-f-string


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

    print(effify(s))  # prints as expected: "-> z"
    Duh!  Am I the only one who feels stupid not thinking of this?
    Although of course it won't work if the string already contains triple
    double quotes.
    I believe this could be got round with some ingenuity (having the effify function parse the string and replace genuine (not embedded in
    single-quotes) triple double quotes with triple single quotes, though
    there are some complications).
    And the effify function can't be put in its own module unless it can be
    passed the globals and/or locals dictionaries as needed for eval to
    use.  Something like this:

    def effify(non_f_str, glob=None, loc=None):
        return eval(f'f"""{non_f_str}"""',
            glob if glob is not None else globals(),
            loc if loc is not None else locals())

    Best wishes
    Rob Cliffe

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Chris Angelico on Wed Jan 25 20:04:56 2023
    On 23/01/2023 18:02, Chris Angelico wrote:
    On Tue, 24 Jan 2023 at 04:56, Johannes Bauer <dfnsonfsduifb@gmx.de> wrote:
    Hi there,

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

    ...

    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:
    If you really want the full power of an f-string, then you're asking
    for the full power of eval(), and that means all the security
    implications thereof, not to mention the difficulties of namespacing.
    Have you considered using the vanilla format() method instead?

    But if you really REALLY know what you're doing, just use eval()
    directly. I don't really see what you'd gain from an f-string. At very
    least, work with a well-defined namespace and eval whatever you need
    in that context.

    Maybe, rather than asking for a way to treat a string as code, ask for
    what you ACTUALLY need, and we can help?

    ChrisA
    Fair enough, Chris, but still ISTM that it is reasonable to ask (perhaps
    for a different use-case) whether there is a way of evaluating a string
    at runtime as if it were an f-string.  We encourage people to ask
    questions on this list, even though the answer will not always be what
    they're hoping for.
    I appreciate that the answer may be "No, because it would be a lot of
    work - and increase the maintenance burden - to support a relatively
    rare requirement".
    Perhaps someone will be inspired to write a function to do it. 😎
    Best wishes
    Rob Cliffe

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Sat Jan 28 06:18:16 2023
    On Sat, 28 Jan 2023 at 05:31, Rob Cliffe via Python-list <python-list@python.org> wrote:
    On 23/01/2023 18:02, Chris Angelico wrote:
    Maybe, rather than asking for a way to treat a string as code, ask for
    what you ACTUALLY need, and we can help?

    ChrisA
    Fair enough, Chris, but still ISTM that it is reasonable to ask (perhaps
    for a different use-case) whether there is a way of evaluating a string
    at runtime as if it were an f-string. We encourage people to ask
    questions on this list, even though the answer will not always be what they're hoping for.

    No, it's not, because that's the "how do I use X to do Y" problem.
    Instead, just ask how to do *what you actually need*. If the best way
    to do that is to eval an f-string, then someone will suggest that.
    But, much much much more likely, the best way to do it would be
    something completely different. What, exactly? That's hard to say,
    because *we don't know what you actually need*. All you tell us is
    what you're attempting to do, which there is *no good way to achieve*.

    I appreciate that the answer may be "No, because it would be a lot of
    work - and increase the maintenance burden - to support a relatively
    rare requirement".

    What about: "No, because it's a terrible TERRIBLE idea, requires that
    you do things horribly backwards, and we still don't even know what
    you're trying to do"?

    Perhaps someone will be inspired to write a function to do it. 😎

    See, we don't know what "it" is, so it's hard to write a function
    that's any better than the ones we've seen. Using eval() to construct
    an f-string and then parse it is TERRIBLE because:

    1) It still doesn't work in general, and thus has caveats like "you
    can't use this type of quote character"
    2) You would have to pass it a dictionary of variables, which also
    can't be done with full generality
    3) These are the exact same problems, but backwards, that led to
    f-strings in the first place
    4) eval is extremely slow and horrifically inefficient.

    For some reason, str.format() isn't suitable, but *you haven't said
    why*, so we have to avoid that in our solutions. So, to come back to
    your concern:

    We encourage people to ask
    questions on this list, even though the answer will not always be what they're hoping for.

    Well, yes. If you asked "how can I do X", hoping the answer would be
    "with a runtime-evaluated f-string", then you're quite right - the
    answer might not be what you were hoping for. But since you asked "how
    can I evaluate a variable as if it were an f-string", the only
    possible answer is "you can't, and that's a horrible idea".

    Don't ask how to use X to do Y. Ask how to do Y.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Fri Jan 27 21:33:32 2023
    Am 25.01.23 um 20:38 schrieb Thomas Passin:

    x = { "y": "z" }
    s = "-> {target}"
    print(s.format(target = x['y']))

    Stack overflow to the rescue:

    No.

    Search phrase:  "python evaluate string as fstring"

    https://stackoverflow.com/questions/47339121/how-do-i-convert-a-string-into-an-f-string

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

    print(effify(s))  # prints as expected: "-> z"

    Great.

    s = '"""'

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

    print(effify(s)) # prints as expected: "-> z"

    print(effify(s))
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 2, in effify
    File "<string>", line 1
    f"""""""""
    ^
    SyntaxError: unterminated triple-quoted string literal (detected at line 1)

    This is literally the version I described myself, except using triple
    quotes. It only modifies the underlying problem, but doesn't solve it.

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Fri Jan 27 21:31:05 2023
    Am 23.01.23 um 19:02 schrieb Chris Angelico:

    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:

    If you really want the full power of an f-string, then you're asking
    for the full power of eval(),

    Exactly.

    and that means all the security
    implications thereof,

    Precisely, as I had stated myself.

    not to mention the difficulties of namespacing.

    Not an issue in my case.

    Have you considered using the vanilla format() method instead?

    Yes. It does not provide the functionality I want. Not even the utterly
    trivial example that I gave. To quote myself again, let's say I have an arbitrary dictionary x (with many nested data structures), I want an
    expression to be evaluated that can access any members in there.

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

    I also want to be able to say things like {'x' * 100}, which .format()
    also does not do.

    In other words: I want the evaluation of a variable as an f-string.


    But if you really REALLY know what you're doing, just use eval()
    directly.

    I do, actually, but I hate it. Not because of the security issue, not
    because of namespaces, but because it does not reliably work:

    s = "{\"x\" * 4}"
    eval("f'" + s + "'")
    'xxxx'

    As I mentioned, it depends on the exact quoting. Triple quotes only
    shift the problem. Actually replacing/escaping the relevant quotation
    marks is also not trivial.

    I don't really see what you'd gain from an f-string.

    The full power of eval.

    At very
    least, work with a well-defined namespace and eval whatever you need
    in that context.

    That's what I'm doing.

    Maybe, rather than asking for a way to treat a string as code, ask for
    what you ACTUALLY need, and we can help?

    I want to render data from a template using an easily understandable
    syntax (like an f-string), ideally using native Python. I want the
    template to make use of Python code constructs AND formatting (e.g. {x['time']['runtime']['seconds'] // 60:02d}).

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Fri Jan 27 21:32:00 2023
    Am 23.01.23 um 17:43 schrieb Stefan Ram:
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))

    x = { "y": "z" }
    def s( x ): return '-> ' + x[ 'y' ]
    print( s( x = x ))

    Except this is not at all what I asked for. The string "s" in my example
    is just that, an example. I want to render *arbitrary* strings "s"
    together with arbitrary dictionaries "x".

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Fri Jan 27 21:43:09 2023
    Am 27.01.23 um 20:18 schrieb Chris Angelico:

    All you tell us is
    what you're attempting to do, which there is *no good way to achieve*.

    Fair enough, that is the answer. It's not possible.

    Perhaps someone will be inspired to write a function to do it. 😎

    See, we don't know what "it" is, so it's hard to write a function
    that's any better than the ones we've seen. Using eval() to construct
    an f-string and then parse it is TERRIBLE because:

    1) It still doesn't work in general, and thus has caveats like "you
    can't use this type of quote character"

    Exactly my observation as well, which is why I was thinking there's
    something else I missed.

    2) You would have to pass it a dictionary of variables, which also
    can't be done with full generality

    Nonsense. I only am passing a SINGLE variable to eval, called "x". That
    is fully general.

    3) These are the exact same problems, but backwards, that led to
    f-strings in the first place

    I don't know what you mean by that.

    4) eval is extremely slow and horrifically inefficient.

    Let me worry about it.

    For some reason, str.format() isn't suitable,

    I don't understand why you fully ignore literally the FIRST example I
    gave in my original post and angrily claim that you solution works when
    it does not:

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

    This. Does. Not. Work.

    I want to pass a single variable as a dictionary and access its members
    inside the expression.

    but *you haven't said
    why*,

    Yes I have, see above.

    Well, yes. If you asked "how can I do X", hoping the answer would be
    "with a runtime-evaluated f-string", then you're quite right - the
    answer might not be what you were hoping for. But since you asked "how
    can I evaluate a variable as if it were an f-string", the only
    possible answer is "you can't, and that's a horrible idea".

    "You can't" would have been sufficient. Pity. Your judgement is
    unnecessary and, frankly, uncalled for as well. Multiple instances you
    claim that you have no idea what I am doing so how would you even begin
    to judge a solution as fit or unfit?

    Don't ask how to use X to do Y. Ask how to do Y.

    You don't have to be angry that my question does not have a solution. I
    will manage and so might you.

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Johannes Bauer on Fri Jan 27 21:30:48 2023
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))
    x = { "y": "z" }
    def s( x ): return '-> ' + x[ 'y' ]
    print( s( x = x ))
    Except this is not at all what I asked for. The string "s" in my example
    is just that, an example. I want to render *arbitrary* strings "s"
    together with arbitrary dictionaries "x".

    I take this to mean that you want to process a dictionary
    name, a string and a dictionary that is only specified as
    late as at run time.

    import string

    name = input( 'name of the dictionary? ' )
    string_ = input( 'string? ' ) # "-> {x['y']}"
    dictionary = eval( input( 'dictionary? ' ))
    print( eval( 'f"""' + string_ + '"""', {name:dictionary} ))

    name of the dictionary? x
    string? -> {x['y']}
    dictionary? { 'y': 'z' }
    z

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Fri Jan 27 23:10:52 2023
    Am 27.01.23 um 21:43 schrieb Johannes Bauer:
    I don't understand why you fully ignore literally the FIRST example I
    gave in my original post and angrily claim that you solution works when
    it does not:

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

    This. Does. Not. Work.

    It's because "you're holding it wrong!". Notice the error message; it
    says that the key 'y' does not exist.


    (base) Apfelkiste:Abschlussmeeting chris$ ipython
    Python 3.8.8 (default, Apr 13 2021, 12:59:45)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: x = { "y": "z" }

    In [2]: s = "-> {x[y]}"

    In [3]: print(s.format(x = x))
    z

    In [4]:

    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Chris Angelico on Fri Jan 27 22:54:48 2023
    Whoa! Whoa! Whoa!
    I appreciate the points you are making, Chris, but I am a bit taken
    aback by such forceful language.

    On 27/01/2023 19:18, Chris Angelico wrote:
    On Sat, 28 Jan 2023 at 05:31, Rob Cliffe via Python-list <python-list@python.org> wrote:
    On 23/01/2023 18:02, Chris Angelico wrote:
    Maybe, rather than asking for a way to treat a string as code, ask for
    what you ACTUALLY need, and we can help?

    ChrisA
    Fair enough, Chris, but still ISTM that it is reasonable to ask (perhaps
    for a different use-case) whether there is a way of evaluating a string
    at runtime as if it were an f-string. We encourage people to ask
    questions on this list, even though the answer will not always be what
    they're hoping for.
    No, it's not, because that's the "how do I use X to do Y" problem.
    Instead, just ask how to do *what you actually need*. If the best way
    to do that is to eval an f-string, then someone will suggest that.
    But, much much much more likely, the best way to do it would be
    something completely different. What, exactly? That's hard to say,
    because *we don't know what you actually need*. All you tell us is
    what you're attempting to do, which there is *no good way to achieve*.
    If the above is addressed to the OP, I can't answer for him.
    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.

    I appreciate that the answer may be "No, because it would be a lot of
    work - and increase the maintenance burden - to support a relatively
    rare requirement".
    What about: "No, because it's a terrible TERRIBLE idea, requires that
    you do things horribly backwards, and we still don't even know what
    you're trying to do"?

    Perhaps someone will be inspired to write a function to do it. 😎
    See, we don't know what "it" is, so it's hard to write a function
    that's any better than the ones we've seen.
    Again, if this is addressed to the OP: I'm not his keeper. 😁
    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 indeed Thomas Passim found this partial
    solution on Stack Overflow:
    def effify(non_f_str: str):
        return eval(f'f"""{non_f_str}"""')
    Using eval() to construct
    an f-string and then parse it is TERRIBLE because:

    1) It still doesn't work in general, and thus has caveats like "you
    can't use this type of quote character"
    2) You would have to pass it a dictionary of variables, which also
    can't be done with full generality
    3) These are the exact same problems, but backwards, that led to
    f-strings in the first place
    4) eval is extremely slow and horrifically inefficient.
    I understand these limitations.  Nonetheless I can conceive that there
    may be scenarios where it is an acceptable solution (perhaps the
    learning tool program I suggested above).
    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.
        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.
        3) Not sure I understand this.
        4) On the fairly rare occasions that I have used eval(), I can't remember speed ever being a consideration.

    For some reason, str.format() isn't suitable, but *you haven't said
    why*, so we have to avoid that in our solutions. So, to come back to
    your concern:

    We encourage people to ask
    questions on this list, even though the answer will not always be what
    they're hoping for.
    Well, yes. If you asked "how can I do X", hoping the answer would be
    "with a runtime-evaluated f-string", then you're quite right - the
    answer might not be what you were hoping for. But since you asked "how
    can I evaluate a variable as if it were an f-string", the only
    possible answer is "you can't, and that's a horrible idea".
    I hope that I have shown that this is a somewhat dogmatic response.

    Don't ask how to use X to do Y. Ask how to do Y.
    Good advice.
    Best wishes
    Rob Cliffe

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Sat Jan 28 10:41:40 2023
    On Sat, 28 Jan 2023 at 10:08, Rob Cliffe via Python-list <python-list@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.)

    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.

    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.

    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}

    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

    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?

    Well, yes. If you asked "how can I do X", hoping the answer would be
    "with a runtime-evaluated f-string", then you're quite right - the
    answer might not be what you were hoping for. But since you asked "how
    can I evaluate a variable as if it were an f-string", the only
    possible answer is "you can't, and that's a horrible idea".
    I hope that I have shown that this is a somewhat dogmatic response.

    And I hope that I have shown that it is fully justified.

    Don't ask how to use X to do Y. Ask how to do Y.
    Good advice.

    Exactly. As I have shown, asking how to use f-strings to achieve this
    is simply not suitable, and there's no useful way to discuss other
    than to argue semantics. If we had a GOAL to discuss, we could find
    much better options.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Rob Cliffe via Python-list on Fri Jan 27 18:38:58 2023
    On 1/27/2023 5:54 PM, Rob Cliffe via Python-list wrote:
    Whoa! Whoa! Whoa!
    I appreciate the points you are making, Chris, but I am a bit taken
    aback by such forceful language.

    I generally agree with asking for what the intent is. In this case it
    seems pretty clear that the OP wants to use these string fragments as templates, and he needs to be able to insert variables into them at
    runtime, not compile time.

    So I think a good response would have been roughly

    "It looks like you want to use these strings as templates, is that
    right? If not, please tell us what you are trying to do, because it's
    hard to help without knowing that. If it's right, here's a way you
    could go about it."

    Short and amiable.

    On 27/01/2023 19:18, Chris Angelico wrote:
    On Sat, 28 Jan 2023 at 05:31, Rob Cliffe via Python-list
    <python-list@python.org> wrote:
    On 23/01/2023 18:02, Chris Angelico wrote:
    Maybe, rather than asking for a way to treat a string as code, ask for >>>> what you ACTUALLY need, and we can help?

    ChrisA
    Fair enough, Chris, but still ISTM that it is reasonable to ask (perhaps >>> for a different use-case) whether there is a way of evaluating a string
    at runtime as if it were an f-string.  We encourage people to ask
    questions on this list, even though the answer will not always be what
    they're hoping for.
    No, it's not, because that's the "how do I use X to do Y" problem.
    Instead, just ask how to do *what you actually need*. If the best way
    to do that is to eval an f-string, then someone will suggest that.
    But, much much much more likely, the best way to do it would be
    something completely different. What, exactly? That's hard to say,
    because *we don't know what you actually need*. All you tell us is
    what you're attempting to do, which there is *no good way to achieve*.
    If the above is addressed to the OP, I can't answer for him.
    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.

    I appreciate that the answer may be "No, because it would be a lot of
    work - and increase the maintenance burden - to support a relatively
    rare requirement".
    What about: "No, because it's a terrible TERRIBLE idea, requires that
    you do things horribly backwards, and we still don't even know what
    you're trying to do"?

    Perhaps someone will be inspired to write a function to do it. 😎
    See, we don't know what "it" is, so it's hard to write a function
    that's any better than the ones we've seen.
    Again, if this is addressed to the OP: I'm not his keeper. 😁
    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 indeed Thomas Passim found this partial solution on Stack Overflow:
    def effify(non_f_str: str):
        return eval(f'f"""{non_f_str}"""')
      Using eval() to construct
    an f-string and then parse it is TERRIBLE because:

    1) It still doesn't work in general, and thus has caveats like "you
    can't use this type of quote character"
    2) You would have to pass it a dictionary of variables, which also
    can't be done with full generality
    3) These are the exact same problems, but backwards, that led to
    f-strings in the first place
    4) eval is extremely slow and horrifically inefficient.
    I understand these limitations.  Nonetheless I can conceive that there
    may be scenarios where it is an acceptable solution (perhaps the
    learning tool program I suggested above).
    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.
        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.
        3) Not sure I understand this.
        4) On the fairly rare occasions that I have used eval(), I can't remember speed ever being a consideration.

    For some reason, str.format() isn't suitable, but *you haven't said
    why*, so we have to avoid that in our solutions. So, to come back to
    your concern:

    We encourage people to ask
    questions on this list, even though the answer will not always be what
    they're hoping for.
    Well, yes. If you asked "how can I do X", hoping the answer would be
    "with a runtime-evaluated f-string", then you're quite right - the
    answer might not be what you were hoping for. But since you asked "how
    can I evaluate a variable as if it were an f-string", the only
    possible answer is "you can't, and that's a horrible idea".
    I hope that I have shown that this is a somewhat dogmatic response.

    Don't ask how to use X to do Y. Ask how to do Y.
    Good advice.
    Best wishes
    Rob Cliffe

    ChrisA


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Christian Gollwitzer on Fri Jan 27 20:56:49 2023
    On 1/27/2023 5:10 PM, Christian Gollwitzer wrote:
    Am 27.01.23 um 21:43 schrieb Johannes Bauer:
    I don't understand why you fully ignore literally the FIRST example I
    gave in my original post and angrily claim that you solution works
    when it does not:

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

    This. Does. Not. Work.

    It's because "you're holding it wrong!". Notice the error message; it
    says that the key 'y' does not exist.


    (base) Apfelkiste:Abschlussmeeting chris$ ipython
    Python 3.8.8 (default, Apr 13 2021, 12:59:45)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: x = { "y": "z" }

    In [2]: s = "-> {x[y]}"

    In [3]: print(s.format(x = x))
    z

    In [4]:

        Christian

    Oops, that's not quite what he wrote.

    You: s = "-> {x[y]}" # Works
    Him: s = "-> {x['y']}" # Fails

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Johannes Bauer on Fri Jan 27 20:51:29 2023
    On 1/27/2023 3:33 PM, Johannes Bauer wrote:
    Am 25.01.23 um 20:38 schrieb Thomas Passin:

    x = { "y": "z" }
    s = "-> {target}"
    print(s.format(target = x['y']))

    Stack overflow to the rescue:

    No.

    Search phrase:  "python evaluate string as fstring"

    https://stackoverflow.com/questions/47339121/how-do-i-convert-a-string-into-an-f-string

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

    print(effify(s))  # prints as expected: "-> z"

    Great.

    s = '"""'

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

    print(effify(s))  # prints as expected: "-> z"

    print(effify(s))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in effify
      File "<string>", line 1
        f"""""""""
               ^
    SyntaxError: unterminated triple-quoted string literal (detected at line 1)

    This is literally the version I described myself, except using triple
    quotes. It only modifies the underlying problem, but doesn't solve it.

    Ok, so now we are in the territory of "Tell us what you are trying to accomplish". And part of that is why you cannot put some constraints on
    what your string fragments are. The example I gave, copied out of your
    earlier message, worked and now you are springing triple quotes on us.

    Stop with the rock management already and explain (briefly if possible)
    what you are up to.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From avi.e.gross@gmail.com@21:1/5 to Johannes Bauer on Sat Jan 28 00:19:21 2023
    May I point out that some dynamic situations can in a sense be normalized?

    The example below posits a dynamically allocated dictionary during run time. But why can't you have a placeholder variable name in place and make your placeholder a link to the dictionary (or other item) before invoking the existing f-string with the placeholder built-in, rather than trying to
    evaluate an F$B"t(B ???

    Of course many situations may not have as much of a possible work-around.
    But as so many have noted, we never got a really good explanation of what
    the OP really wants to do. There have been replies that may be suitable solutions and some clearly have potential to be security holes if you let
    the users dynamically create strings to be evaluated.

    In some languages, many of the facets of the language can be passed along as
    a function with some name to be used in functional programming techniques
    and this can be very useful. The "operator" module can be used for quite a
    few things like operator.add or operator.__add__ or operator.concat and many more. If the logic used to evaluate an f-string (and for that matter the
    other string variants like b'..' and r'...') could be encapsulated in a function like that, it would be potentially usable as in passing something
    like dangerous_operator.f_string and a list of strings and having that
    return a list of evaluated strings.

    The fact that something like this is not known to the people here may hint that it is not something considered safe to use by amateurs. But then again, anyone who wants to can use eval() as Chris points out.

    Of course, there may be other reasons too. An f-string is evaluated in a context that may be different if a string is passed along and then looked at
    in another context.

    -----Original Message-----
    From: Python-list <python-list-bounces+avi.e.gross=gmail.com@python.org> On Behalf Of Stefan Ram
    Sent: Friday, January 27, 2023 4:31 PM
    To: python-list@python.org
    Subject: Re: Evaluation of variable as f-string

    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))
    x = { "y": "z" }
    def s( x ): return '-> ' + x[ 'y' ]
    print( s( x = x ))
    Except this is not at all what I asked for. The string "s" in my
    example is just that, an example. I want to render *arbitrary* strings "s" >together with arbitrary dictionaries "x".

    I take this to mean that you want to process a dictionary
    name, a string and a dictionary that is only specified as
    late as at run time.

    import string

    name = input( 'name of the dictionary? ' ) string_ = input( 'string? ' ) #
    "-> {x['y']}"
    dictionary = eval( input( 'dictionary? ' )) print( eval( 'f"""' + string_ + '"""', {name:dictionary} ))

    name of the dictionary? x
    string? -> {x['y']}
    dictionary? { 'y': 'z' }
    z


    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Thomas Passin on Sat Jan 28 14:28:47 2023
    On 2023-01-27 20:56:49 -0500, Thomas Passin wrote:
    On 1/27/2023 5:10 PM, Christian Gollwitzer wrote:
    Am 27.01.23 um 21:43 schrieb Johannes Bauer:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    KeyError: "'y'"

    This. Does. Not. Work.

    It's because "you're holding it wrong!". Notice the error message; it
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    says that the key 'y' does not exist.
    [...]
    In [1]: x = { "y": "z" }
    In [2]: s = "-> {x[y]}"
    In [3]: print(s.format(x = x))
    z
    In [4]:

    Oops, that's not quite what he wrote.

    You: s = "-> {x[y]}" # Works
    Him: s = "-> {x['y']}" # Fails

    That was the point.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmPVIwoACgkQ8g5IURL+ KF3vvA/+KRuvg1fieIbDV7iiaqfMQn36vQzJJoH1UDrkpZOj5X8fn+d2CBF95LTH TQ5jXlOgMfbQxuVMzGVSM+57dfRyPyNDLXfaKGS5A30cvy5pac0nvv0gUbxhHORG AUP3vscPXS/J4hEB0RrLXsx3Z6E6KClrXDxynIYlFAiFnLlpLhuc6oAwnxzlUuy2 qmycgwpCteg4fPESIQfXxIJyRwgSc/04uM+qu6Dngf+84tCZsaiy5/BlIDnd2UDm bP2xH93bPpJVjtDEtLnGruLJAed3RgfFHcmk88c4K229GLU2W/fONBFExoXx6EJk s2MVT1pLWR53haXn7fQ+SpvturetP9+yLYq8ZgZIQPM5gU843v7UtdGfytnKy6BE MaVTos2stOQY002xbgqixdJ9igez7QPN0shlU+KHMn3edSwwFB4yzaL4dHSkX7dN VKJpzT/Eeic1C9qglfhkvm0oG42P6hJ+TwVsQxKBhwu+rtysNRm3XVetMYYxQ47w 1z+VNy7AQHoSyLr+DQOAH1EWVO0dKSFqYOhUD02UqyzYjpNQm5JYL5p1mKqvFkt8 F989d3dwT8g6fNrYcWklSd+uuXLzlLydTD20/1SaT42cWBXTlDpji67Soa9rPK9+ G5LDOUeyDv6hLe5riI9Gbbz2ASjilBNl8MxWLBt
  • From Peter J. Holzer@21:1/5 to Johannes Bauer on Sat Jan 28 14:41:13 2023
    On 2023-01-27 21:43:09 +0100, Johannes Bauer wrote:
    x = { "y": "z" }
    s = "-> {x['y']}"
    print(s.format(x = x))
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    KeyError: "'y'"

    This. Does. Not. Work.

    I want to pass a single variable as a dictionary and access its members inside the expression.

    You can do that (see other responses), but you can't have arbitrary
    Python expressions inside a format string.

    It works with f-strings because f-strings are a compiler construct. The f-string never exists at run-time. Instead the compiler transforms
    f"-> {x['y']}"
    into the equivalent of
    "-> " + format_value(x["y"]) + ""

    So either you need to pass it to the Python compiler (via eval), or you
    need to implement enough of a Python parser/interpreter to cover the
    cases you are interested in. The latter might be an interesting
    exercise, but I would suggest looking at existing template engines like
    Jinja2 for production purposes.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmPVJfQACgkQ8g5IURL+ KF1b7BAAnTOlOfC7yfdI+QiiFpboU2RKEb7/sUYESdIXrycKBUU10m37E0a2/huA WOmd2oKtA85hb8oig0RuwY3IxxuI7hl1MpAgUmXoDSUHijNcA/pUj6Cv2N5nCSHL RhiwPspe2FnlWZ0HpNyNBLhYg9e7nKdzVl0Ejn6RABzQildOP63V+ayLqu/p+SRy nhBXO//fzBGvN36oJYfuaJxkzA/XhU1Dbyx4QYRa4jWoLAn3jDO0CWFvaGaydV2q CkQ6dfBHqeQA9jC5Jg02mpsvSnYmHG5yfJgAOKykN8Zbc/v9yHUM1qNYK/OlKjm5 39ZiT38SiPwzqqznYdCYY8D6DOGHAalG3YIyxI9JS7JZWPVpx2Ugtm/eA1ediS3d ivs38Ejpb9npTa4uzGutmcZk4zVUg52SYpUPNloI1Catzpe6uPfX9c+3L9YPzxJ0 rBgkZns9UTyRhv7AdOBdlTap80BVjjuoRqDUYuieCoF573OduKj5j9oNJh2XZWtY RAch08NfyJGMhm1XEmOLTZp3ASn1ANxnsxQji+MJnT+8TuROLmLVClaAa8N+musx c3DmDTjlIV459rL34daEw2ozSmred/P9eLhXBtH2Fj1cteyfNuWAlji8PtkbVATJ Le18mVapU5JehFlMkgP6g6ZfLxmaJhmYc40bo6l
  • From Peter J. Holzer@21:1/5 to Johannes Bauer on Sat Jan 28 15:22:18 2023
    On 2023-01-27 21:31:05 +0100, Johannes Bauer wrote:
    But if you really REALLY know what you're doing, just use eval()
    directly.

    I do, actually, but I hate it. Not because of the security issue, not
    because of namespaces, but because it does not reliably work:

    s = "{\"x\" * 4}"
    eval("f'" + s + "'")
    'xxxx'

    That's exactly the result I expected. What did you expect?

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmPVL5IACgkQ8g5IURL+ KF1XFw//S5aw9nuVfBANoC0J4wHDZkvFIz5O26CU3u6TfXT5rYnQVGwfJj74T0xk kpV75IZroFRDlj5wIAbCeGGVWxatEz+n5eBGdUwH67lkRbfKWoE+cuXxDcMBpABQ StS7eQXFBp+m4xIu5F7iRrwe3YlqPuf8rDqggVlMmlEgQJV7lTBwkfFbh//rp7Y8 LlPRh/99QKCkDPmdUHJkQ7J2cMgxN/7sjJcd7RxA9I15U++Nj/5le8KF2BjTdv5U zplg5+G430p1vlQz5oZknrvClaaQUIB7aJHaL+N32o7vmH5MQ6qFReQP3sbGc+Ua NmVnHeCZyH8LasmVV09IiBAAemOw5nWv3rEkaZ4zX/IfzbOgjq/Y5Bfpa7KLVCB/ 1YlmgBbPBqM+JVtVlEV6+VgJUi1U1K0t8UiOgVWm+/tFDP1aTbcxgH6cT7rWy/+6 Cf2Ho+BZRCAARhIhwTTQjmmmBCM08mgMIDtpvQH502cNPV1aefei9OcFl5jKlAec tpIVL0i+Fv4skDePLhDRP51l3lasiwXLud4nUaLkIPrDiTat1qw+66NvuXI/P2wm 3OiUIlT91uYH2zNM4IvzQdvPa7ezwPp1VDtLXIU5KVHyywe9PFhqWhXaPwk2aS7F pG72tq8woxkDa3744mZYJwFGEQzJKUusphRuYt1
  • From Johannes Bauer@21:1/5 to All on Sat Jan 28 20:57:23 2023
    Am 28.01.23 um 00:41 schrieb Chris Angelico:
    On Sat, 28 Jan 2023 at 10:08, Rob Cliffe via Python-list <python-list@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.

    An arrogant bully's rationale. Personally, I'm fine with it. I've been
    to Usenet for a long time, in which this way of "educating" people was considered normal. But I do think it creates a deterring, toxic
    environment and reflects back to you as a person negatively.

    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.

    Exactly. This is precisely what I want to avoid. Essentially, proper
    quotation of such a string requires to write a fully fledged f-string
    parser, in which case the whole problem solves itself.

    Don't ask how to use X to do Y. Ask how to do Y.
    Good advice.

    Exactly. As I have shown, asking how to use f-strings to achieve this
    is simply not suitable, and there's no useful way to discuss other
    than to argue semantics. If we had a GOAL to discuss, we could find
    much better options.

    I was not asking how to use f-strings. I was asking to evaluate a string
    *as if it were* an f-string. Those are two completely different things
    which you entirely ignored.

    In other words, if there were a magic function:

    evalfstring(s, x = x)

    That would have been the ideal answer. There does not seem to be one,
    however. So I'm back to silly workarounds.

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Sat Jan 28 20:50:52 2023
    Am 28.01.23 um 02:51 schrieb Thomas Passin:

    This is literally the version I described myself, except using triple
    quotes. It only modifies the underlying problem, but doesn't solve it.

    Ok, so now we are in the territory of "Tell us what you are trying to accomplish". And part of that is why you cannot put some constraints on
    what your string fragments are.  The example I gave, copied out of your earlier message, worked and now you are springing triple quotes on us.

    It works in this particular case, yes. Just like the example I gave in
    my original case:

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

    "works" if there are no apostrophes used. And just like

    eval("f\"" + s + "\"")

    "works" if there are no quotation marks used.

    I don't want to have to care about what quotation is used inside the
    string, as long as it could successfully evaluate using the f-string
    grammar.

    Stop with the rock management already and explain (briefly if possible)
    what you are up to.

    I have a string. I want to evaluate it as if it were an f-string. I.e.,
    there *are* obviously restrictions that apply (namely, the syntax and
    semantics of f-strings), but that's it.

    Best,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Sat Jan 28 21:02:03 2023
    Am 27.01.23 um 23:10 schrieb Christian Gollwitzer:
    Am 27.01.23 um 21:43 schrieb Johannes Bauer:
    I don't understand why you fully ignore literally the FIRST example I
    gave in my original post and angrily claim that you solution works
    when it does not:

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

    This. Does. Not. Work.

    It's because "you're holding it wrong!". Notice the error message; it
    says that the key 'y' does not exist.

    Ah, that is neat! I didn't know that. Thanks for the info.

    In my case, I do also however want to have some functionality that
    actually does math or even calls functions. That would be possible with templates or f-strings, but not format:


    x = { "t": 12345 }
    s = "{x['t'] // 60:02d}:{x['t'] % 60:02d}"
    print(s.format(x = x))
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    KeyError: "'t'"

    and

    s = "{x[t] // 60:02d}:{x[t] % 60:02d}"
    print(s.format(x = x))

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ValueError: Only '.' or '[' may follow ']' in format field specifier

    but of course:

    print(f"{x['t'] // 60:02d}:{x['t'] % 60:02d}")
    205:45

    Best,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Johannes Bauer on Sun Jan 29 12:05:51 2023
    On Sun, 29 Jan 2023 at 11:53, Johannes Bauer <dfnsonfsduifb@gmx.de> wrote:
    I don't want to have to care about what quotation is used inside the
    string, as long as it could successfully evaluate using the f-string
    grammar.


    Not possible. An f-string can contain other f-strings, and it is
    entirely possible to use EVERY quote type. So you can never add quotes
    around the outside of a string and then evaluate it as an f-string,
    without making sure that it doesn't already contain that string.

    (That MAY be changing in a future version of Python, but it's currently true.)

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Johannes Bauer on Sun Jan 29 12:09:16 2023
    On Sun, 29 Jan 2023 at 11:56, Johannes Bauer <dfnsonfsduifb@gmx.de> wrote:

    Am 28.01.23 um 00:41 schrieb Chris Angelico:
    On Sat, 28 Jan 2023 at 10:08, Rob Cliffe via Python-list <python-list@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.

    An arrogant bully's rationale. Personally, I'm fine with it. I've been
    to Usenet for a long time, in which this way of "educating" people was considered normal. But I do think it creates a deterring, toxic
    environment and reflects back to you as a person negatively.

    Arrogant bully? Or someone who has tried *multiple times* to explain
    to you that what you're asking for is IMPOSSIBLE, and you need to ask
    a better question if you want a better answer?

    If that's "bullying", then fine, ban me for bullying, and go find
    somewhere else where you'll be coddled and told that your question is
    fine, it's awesome, and yes, wouldn't it be nice if magic were a
    thing.

    Exactly. This is precisely what I want to avoid. Essentially, proper quotation of such a string requires to write a fully fledged f-string
    parser, in which case the whole problem solves itself.

    Don't ask how to use X to do Y. Ask how to do Y.
    Good advice.

    Exactly. As I have shown, asking how to use f-strings to achieve this
    is simply not suitable, and there's no useful way to discuss other
    than to argue semantics. If we had a GOAL to discuss, we could find
    much better options.

    I was not asking how to use f-strings. I was asking to evaluate a string
    *as if it were* an f-string. Those are two completely different things
    which you entirely ignored.

    They're not different things, because what you asked for is NOT
    POSSIBLE without the caveats that I gave. It is *fundamentally not
    possible* to "evaluate a string as if it were an f-string", other than
    by wrapping it in an f-string and evaluating it - with the
    consequences of that.

    In other words, if there were a magic function:

    evalfstring(s, x = x)

    That would have been the ideal answer. There does not seem to be one, however. So I'm back to silly workarounds.


    Right. Exactly. Now if you'd asked for what you REALLY need, maybe
    there'd be a solution involving format_map, but no, you're so utterly intransigent that you cannot adjust your question to fit reality.

    If that makes me a bad guy, then fine. I'll be the bad guy.

    But you're not going to change the laws of physics.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Johannes Bauer on Sun Jan 29 02:18:43 2023
    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    I have a string. I want to evaluate it as if it were an f-string. I.e.,
    there *are* obviously restrictions that apply (namely, the syntax and >semantics of f-strings), but that's it.

    (This message was written for Usenet. If you read it in a
    mailing list or the Web, it has been stolen from Usenet.)

    So, you want your run-time client or run-time user to have the
    same choices as someone who is just writing python source code
    and is using an f-string?

    Then what about,

    name = input( 'name of the dictionary? ' )
    s = input( 'string? ' )
    dictionary = eval( input( 'dictionary? ' ))
    print( eval( s, {name:dictionary} ))

    ? Here are four transcripts:

    name of the dictionary? x
    string? f"-> {x['y']}"
    dictionary? { "y": "z" }
    z

    name of the dictionary? x
    string? f'-> {x["y"]}'
    dictionary? { "y": "z" }
    z

    name of the dictionary? x
    string? f"-> {x['''y''']}"
    dictionary? { "y": "z" }
    z

    name of the dictionary? x
    string? f'-> {x["""y"""]}'
    dictionary? { "y": "z" }
    z

    .

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Stefan Ram on Sun Jan 29 15:47:47 2023
    On Sun, 29 Jan 2023 at 14:36, Stefan Ram <ram@zedat.fu-berlin.de> wrote:

    Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
    I have a string. I want to evaluate it as if it were an f-string. I.e., >there *are* obviously restrictions that apply (namely, the syntax and >semantics of f-strings), but that's it.

    (This message was written for Usenet. If you read it in a
    mailing list or the Web, it has been stolen from Usenet.)


    I'm curious as to the copyright protections available to you, but if
    you're going to threaten python-list's owners with legal action for
    daring to rebroadcast a public post, I would have to recommend that
    you get promptly banned from the list in order to reduce liability.

    What's so bad about mailing lists that you don't want your messages to
    be seen on them?

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Johannes Bauer on Sat Jan 28 23:27:58 2023
    On 1/28/2023 2:50 PM, Johannes Bauer wrote:
    Am 28.01.23 um 02:51 schrieb Thomas Passin:

    This is literally the version I described myself, except using triple
    quotes. It only modifies the underlying problem, but doesn't solve it.

    Ok, so now we are in the territory of "Tell us what you are trying to
    accomplish". And part of that is why you cannot put some constraints
    on what your string fragments are.  The example I gave, copied out of
    your earlier message, worked and now you are springing triple quotes
    on us.

    It works in this particular case, yes. Just like the example I gave in
    my original case:

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

    "works" if there are no apostrophes used. And just like

    eval("f\"" + s + "\"")

    "works" if there are no quotation marks used.

    I don't want to have to care about what quotation is used inside the
    string, as long as it could successfully evaluate using the f-string
    grammar.

    Stop with the rock management already and explain (briefly if
    possible) what you are up to.

    I have a string. I want to evaluate it as if it were an f-string. I.e.,
    there *are* obviously restrictions that apply (namely, the syntax and semantics of f-strings), but that's it.

    Well, yes, we do see that. What we don't see is what you want to
    accomplish by doing it, and why you don't seem willing to accept some restrictions on the string fragments so that they will evaluate correctly.

    IOW, perhaps there is a more practical way to accomplish what you want.
    Except that we don't know what that is.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Sun Jan 29 10:05:31 2023
    Am 29.01.23 um 02:09 schrieb Chris Angelico:

    The exact same points have already been made, but not listened to.
    Sometimes, forceful language is required in order to get people to
    listen.

    An arrogant bully's rationale. Personally, I'm fine with it. I've been
    to Usenet for a long time, in which this way of "educating" people was
    considered normal. But I do think it creates a deterring, toxic
    environment and reflects back to you as a person negatively.

    Arrogant bully? Or someone who has tried *multiple times* to explain
    to you that what you're asking for is IMPOSSIBLE, and you need to ask
    a better question if you want a better answer?

    In literally your first answer you resorted to aggressive language and
    implied that what I asked wasn't what I actually wanted. It was.

    Also note that in your first answer you did not answer "sorry, this is
    not possible", which would have been completely sufficient as an answer. Instead you tried your best at guesswork, implying I didn't know what I
    was doing.

    So, yes, absolutely toxic behavior. I fully stand by that judgement of mine.

    I'll go a step further and again repeat that THIS sort of behavior is
    what gives open source forums a bad rep. There's always a Lennart
    Poettering, an Ulrich Drepper or maybe a Chris Angelico around who may
    have great technical skill but think they can treat people like shit.

    If that's "bullying", then fine, ban me for bullying, and go find
    somewhere else where you'll be coddled and told that your question is
    fine, it's awesome, and yes, wouldn't it be nice if magic were a
    thing.

    LOL, "ban you"? What the heck are you talking about, my friend?

    I don't need to be coddled by you. I'm trying to give you the favor of
    honest feedback, which is that you sound like an utter bully. If you
    don't care, that is totally fine by me.

    They're not different things, because what you asked for is NOT
    POSSIBLE without the caveats that I gave. It is *fundamentally not
    possible* to "evaluate a string as if it were an f-string", other than
    by wrapping it in an f-string and evaluating it - with the
    consequences of that.

    Yeah that sucks, unfortunately. But I'll live.

    In other words, if there were a magic function:

    evalfstring(s, x = x)

    That would have been the ideal answer. There does not seem to be one,
    however. So I'm back to silly workarounds.

    Right. Exactly. Now if you'd asked for what you REALLY need, maybe
    there'd be a solution involving format_map, but no, you're so utterly intransigent that you cannot adjust your question to fit reality.

    Does format_map do exactly what f-strings can do? Can I pass arbitrary functions and Python expressions insode a format_map? No? Of course not.
    Then it does not answer the question.

    If that makes me a bad guy, then fine. I'll be the bad guy.

    Awww, it's adorable how you're trying to frame yourself as the victim.
    I'll be here if you need a hug, buddy.

    But you're not going to change the laws of physics.

    Yeah we'll have to disagree about the fact that it's the "laws of
    physics" preventing a specific implementation of a Python function.

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Sun Jan 29 10:18:00 2023
    Am 29.01.23 um 05:27 schrieb Thomas Passin:

    Well, yes, we do see that.  What we don't see is what you want to
    accomplish by doing it, and why you don't seem willing to accept some restrictions on the string fragments so that they will evaluate correctly.

    I'll have to accept the restrictions. That's a good enough answer for
    me, actually. I was just thinking that possibly there's something like
    (made-up code):

    x = { "foo": "bar" }
    fstr = string.fstring_compile(s)
    fstr.eval(x = x)

    Which I didn't know about. It would make sense to me, but possibly not
    enough of a usecase to make it into Python. The format() flavors do not

    IOW, perhaps there is a more practical way to accomplish what you want. Except that we don't know what that is.

    Well, I don't know. I pretty much want a generic Python mechanism that
    allows for exactly what f-strings do: execute arbitrary Python snippets
    of code and format them in one go. In other words, I want to be able to
    do things like that, given an *arbitrary* dictionary x and a string s
    (which has the only restriction that its content needs to be vald
    f-string grammar):

    x = {
    "d": 12,
    "t": 12345,
    "dt": datetime.datetime,
    "td": datetime.timedelta
    }
    s = "{x['d']:09b} {'->' * (x['d'] // 3)} {(x['dt'](2000, 1, x['d']) + x['td'](120)).strftime('%y.%m.%d')} {'<-' * (x['d'] // 4)}"
    q = magic_function(s, x = x)

    and have "q" then be

    '000001100 ->->->-> 00.05.11 <-<-<-'

    I believe the closest solution would be using a templating mechanism
    (like Mako), but that has slightly different syntax and doesn't do
    string formatting as nice as f-strings do. f-strings really are the
    perfect syntax for what I want to do.

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Gollwitzer@21:1/5 to All on Sun Jan 29 12:09:59 2023
    Am 28.01.23 um 02:56 schrieb Thomas Passin:
    On 1/27/2023 5:10 PM, Christian Gollwitzer wrote:
    Am 27.01.23 um 21:43 schrieb Johannes Bauer:
    I don't understand why you fully ignore literally the FIRST example I
    gave in my original post and angrily claim that you solution works
    when it does not:

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

    This. Does. Not. Work.

    It's because "you're holding it wrong!". Notice the error message; it
    says that the key 'y' does not exist.


    (base) Apfelkiste:Abschlussmeeting chris$ ipython
    Python 3.8.8 (default, Apr 13 2021, 12:59:45)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: x = { "y": "z" }

    In [2]: s = "-> {x[y]}"

    In [3]: print(s.format(x = x))
    z

    In [4]:

         Christian

    Oops, that's not quite what he wrote.

    You: s = "-> {x[y]}"    # Works
    Him: s = "-> {x['y']}"  # Fails

    You might want to reconsider why I could have possibly written this
    message....

    Christian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Passin@21:1/5 to Christian Gollwitzer on Sun Jan 29 13:52:02 2023
    On 1/29/2023 6:09 AM, Christian Gollwitzer wrote:
    Am 28.01.23 um 02:56 schrieb Thomas Passin:
    On 1/27/2023 5:10 PM, Christian Gollwitzer wrote:
    Am 27.01.23 um 21:43 schrieb Johannes Bauer:
    I don't understand why you fully ignore literally the FIRST example
    I gave in my original post and angrily claim that you solution works
    when it does not:

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

    This. Does. Not. Work.

    It's because "you're holding it wrong!". Notice the error message; it
    says that the key 'y' does not exist.


    (base) Apfelkiste:Abschlussmeeting chris$ ipython
    Python 3.8.8 (default, Apr 13 2021, 12:59:45)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: x = { "y": "z" }

    In [2]: s = "-> {x[y]}"

    In [3]: print(s.format(x = x))
    z

    In [4]:

         Christian

    Oops, that's not quite what he wrote.

    You: s = "-> {x[y]}"    # Works
    Him: s = "-> {x['y']}"  # Fails

    You might want to reconsider why I could have possibly written this message....

    I might .. or I might wish you had actually said what you wanted to
    convey ...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Johannes Bauer on Mon Jan 30 01:10:50 2023
    On 2023-01-29 10:18:00 +0100, Johannes Bauer wrote:
    Am 29.01.23 um 05:27 schrieb Thomas Passin:
    IOW, perhaps there is a more practical way to accomplish what you want. Except that we don't know what that is.

    Well, I don't know. I pretty much want a generic Python mechanism that
    allows for exactly what f-strings do: execute arbitrary Python snippets of code

    That exists. Use eval (or exec).

    and format them in one go.

    Include an f-string in the code you eval.

    In other words, I want to be able to do things like that, given an *arbitrary* dictionary x and a string s

    As I wrote before: An f-string isn't a string. It's a grammatical
    construct. So you want to execute Python code which is what eval and
    exec do.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmPXCwUACgkQ8g5IURL+ KF0hhw//X9KhD42GEs2MpaOYk7+Uf3gATgVlQV+4e7bYUO28qm1O206iHiLNRA/p e8MINCMVq1pbXXHwqwJDchg5qYK+bj20A0u50GrCBjHCUM3oWP+ru/Ve0N4uvTJu DVa3kZ/RS+mVo4+H8cAZPY13NHtTNsNNLHIrx0eJDxqyFLwc7xBVmrowsXTUGVMG JgxwyD5YpONn0F9iPJWc0WrKeMMFyZxF4sfmYPXxvkgLAnlXbFPnIGrv5zsMvybE gs81gjTzQf10OJAphEFFhWRBuy/PL2Qy4jtyIsskSv5a5Z0BuW38us+iXOok9SJM iLnq4GH4LGYznoLp9uMY9UPGtVaEzKqPI7MefzUS2PiK2QfO+lJMPCNFgOJ3/NcQ QnKDSEd12IXgFWBEfdqrml0UWSL+oxwzzKzKwMT+9IwtGbQcquRXUicmzGDQvGVb gln4HccfqRkOw7djE3Y1TPLL5MFuVzxi9aBKyZd14GA0CV2qysCa6GaqoSAmGZOX 7YpBPJ8F38phqDw7RNEzcIRVLTrFsdlQNpazmzAKZr5QEoqKvoePUc2VMb8zL9Tp vI25cYAuoci9p7uwaSK2HvmjOZIWGdcJFE+Q6zkk9FqlBJrHijt0MJsTAsudMwXf pMlaaLqeqzd1OTkArrowAfAo0IF61zRwW1baT7T
  • From Stefan Ram@21:1/5 to Stefan Ram on Tue Jan 31 18:17:23 2023
    ram@zedat.fu-berlin.de (Stefan Ram) writes:
    Then what about,
    name = input( 'name of the dictionary? ' )
    s = input( 'string? ' )
    dictionary = eval( input( 'dictionary? ' ))
    print( eval( s, {name:dictionary} ))

    This works always if the client or user adds the "f" for the
    f-string at the start of his string himself. The next program shows
    an approach that will not work always, but often.

    def evaluate_as_fstring( s ):
    if '"""' in s and "'''" in s:
    raise Exception( "String contains both \"\"\" and '''!" )
    elif '"""' in s: return eval( "f'''" + s + "'''" )
    else: return eval( 'f"""' + s + '"""' )

    x ={ "y": "z" }

    print( evaluate_as_fstring( "-> {x['y']}" ))
    print( evaluate_as_fstring( '-> {x["y"]}' ))
    print( evaluate_as_fstring( "-> {x['''y''']}" ))
    print( evaluate_as_fstring( '-> {x["""y"""]}' ))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Chris Angelico on Sat Jan 28 16:39:49 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@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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Wed Feb 1 09:33:45 2023
    On Wed, 1 Feb 2023 at 09:14, Rob Cliffe via Python-list <python-list@python.org> wrote:
    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.

    It's an objectively bad idea. If the OP wants to do it, well, it's a
    free world, but that doesn't mean I'm going to sugarcoat it and say
    "oh yes, yes, you are totally right to do that".

    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?

    I don't think so, but there might be some value in a dictionary
    containing all available variables. It would have the same "don't
    depend on writing" caveats that locals() has (or would be specifically
    defined as a copy and thus disconnected), so its value would be
    limited. And it would probably STILL be imperfect, because perfection
    would require that it be a compiler construct, due to the way that
    nonlocals are implemented.

    class Destructible:
    ... def __init__(self, name): self.name = name
    ... def __del__(self): print("Deleting", self.name)
    ...
    def func():
    ... x = Destructible("x")
    ... y = Destructible("y")
    ... return lambda: x
    ...
    func()
    Deleting y
    <function func.<locals>.<lambda> at 0x7ff8c9897ce0>

    The compiler is free to dispose of y as soon as func ends, but x has
    to be retained for the inner function. So if there were any function
    that could return every readable variable, it would have to force both
    x and y to be retained; as such, it would have to be a compiler
    construct. And given what happened with star imports in functions as
    of Python 3, I am highly dubious that such a pessimisation would ever
    be implemented.

    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!

    Exactly. This sort of thing is why the OP's idea as written is so bad:
    it will cause many unnecessary corner cases, where the much simpler
    idea of working it around format_map will actually behave sanely.

    So I do not apologize for calling it a bad idea. It is a bad idea.
    Lying about it won't change anything and won't help anyone.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johannes Bauer@21:1/5 to All on Mon Feb 6 20:21:39 2023
    Am 31.01.23 um 23:33 schrieb Chris Angelico:

    It's an objectively bad idea. If the OP wants to do it, well, it's a
    free world, but that doesn't mean I'm going to sugarcoat it and say
    "oh yes, yes, you are totally right to do that".

    It is pretty baffling how convinced you are of yourself. It would be
    amusing if it weren't so toxic.

    Exactly. This sort of thing is why the OP's idea as written is so bad:
    it will cause many unnecessary corner cases, where the much simpler
    idea of working it around format_map will actually behave sanely.

    Except, as I have pointed out over and over and over again: your
    "solution" does not fit the criteria.

    You're calling a lugnut an "objectively bad idea" because obviously in
    their right mind would want to use a nail. You're completely ignoring
    what my intended solution provides and claiming that your non-solution
    solves the problem.

    It. Does. Not.

    I find it shocking that you are unable to grasp a concept so simple.

    So I do not apologize for calling it a bad idea. It is a bad idea.
    Lying about it won't change anything and won't help anyone.

    You know what's objectively worse than a solution that has drawbacks?
    One that doesn't solve the issue in *the slightest*, just as *all* of
    your suggestions have.

    It's quite ridiculous that you critize a solution with such conviction
    but are only able to provide completely dysfunctional "alternatives",
    utterly broken and without a hint of the requested functionaly. Yet you
    claim your solution is "objectively better". This is totally nuts.

    I withdraw my earlier statement that you seem to be technically
    competent. You have absolutely and utterly no clue what you are talking
    about, yet reiterate and advocate "solutions" that are none. This is
    pathetic.

    Cheers,
    Johannes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rob Cliffe@21:1/5 to Chris Angelico on Tue Feb 7 15:12:08 2023
    [re-sending this to both the list and to Chris, as a prior send to the
    list only was bounced back]
    On 31/01/2023 22:33, Chris Angelico wrote:

    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?
    I don't think so, but there might be some value in a dictionary
    containing all available variables. It would have the same "don't
    depend on writing" caveats that locals() has (or would be specifically defined as a copy and thus disconnected), so its value would be
    limited. And it would probably STILL be imperfect, because perfection
    would require that it be a compiler construct, due to the way that
    nonlocals are implemented.
    Does that mean that it is not possible to have a (built-in) function
    that would construct and return a dictionary of all available variables
    and their values?  If it were possible, it could be useful, and there
    would be no impact on Python run-time speed if it were only constructed
    on demand.

    Best wishes
    Rob

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Rob Cliffe on Tue Feb 7 16:41:45 2023
    Rob Cliffe <rob.cliffe@btinternet.com> writes:
    Does that mean that it is not possible to have a (built-in) function
    that would construct and return a dictionary of all available variables
    and their values?  If it were possible, it could be useful, and there
    would be no impact on Python run-time speed if it were only constructed
    on demand.

    Here's a quick attempt to get local and non-local names as a set.
    It might only work under some implementations of Python.

    main.py

    set_class = set

    def f():
    x = 0
    def g():
    set = set_class()
    for n in g.__qualname__.split( '.' ):
    if n != '<locals>':
    set = set.union( set_class( eval( n ).__code__.co_varnames ))
    print( set )
    g()
    f()

    output

    {'n', 'set', 'x'}

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Stefan Ram on Wed Feb 8 05:52:14 2023
    On Wed, 8 Feb 2023 at 05:30, Stefan Ram <ram@zedat.fu-berlin.de> wrote:

    Rob Cliffe <rob.cliffe@btinternet.com> writes:
    Does that mean that it is not possible to have a (built-in) function
    that would construct and return a dictionary of all available variables
    and their values? If it were possible, it could be useful, and there
    would be no impact on Python run-time speed if it were only constructed
    on demand.

    Here's a quick attempt to get local and non-local names as a set.
    It might only work under some implementations of Python.

    main.py

    set_class = set

    def f():
    x = 0
    def g():
    set = set_class()
    for n in g.__qualname__.split( '.' ):
    if n != '<locals>':
    set = set.union( set_class( eval( n ).__code__.co_varnames ))
    print( set )
    g()
    f()

    output

    {'n', 'set', 'x'}


    Breaks on wrapped functions. Also, how are you going to get the values
    of those variables?

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Rob Cliffe on Wed Feb 8 04:46:52 2023
    On Wed, 8 Feb 2023 at 02:12, Rob Cliffe <rob.cliffe@btinternet.com> wrote:

    [re-sending this to both the list and to Chris, as a prior send to the
    list only was bounced back]
    On 31/01/2023 22:33, Chris Angelico wrote:

    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?
    I don't think so, but there might be some value in a dictionary
    containing all available variables. It would have the same "don't
    depend on writing" caveats that locals() has (or would be specifically defined as a copy and thus disconnected), so its value would be
    limited. And it would probably STILL be imperfect, because perfection
    would require that it be a compiler construct, due to the way that nonlocals are implemented.
    Does that mean that it is not possible to have a (built-in) function
    that would construct and return a dictionary of all available variables
    and their values? If it were possible, it could be useful, and there
    would be no impact on Python run-time speed if it were only constructed
    on demand.


    It can't be a built-in function and also be 100% reliable; and if it's
    a special compiler construct, its presence in your code would have
    semantic impact on all nested functions - even if you never call it:

    def func():
    x = Obj()
    def inner():
    if False: get_vars
    return inner

    x can no longer be disposed of, just in case you call inner and get the vars.

    And quite frankly, I don't think this functionality justifies a magic
    compiler construct and consequent keyword. But a builtin won't be
    reliable.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)