f-string anomaly

Terry Reedy tjreedy at udel.edu
Sun May 13 22:08:32 EDT 2018


On 5/13/2018 3:22 PM, Ken Kundert wrote:

Please do not double post.

> I am seeing an unexpected difference between the behavior of the string
> format method and f-strings.

Read 
https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals 
carefully.

> Here is an example:
> 
>      import sys, os
>      from inform import error, os_error
> 
>      class mydict(dict):
>          def __format__(self, template):
>              print('Template:', template)
>              return ', '.join(template.format(v, k=k, v=v) for k, v in
> self.items())
> 
> 
>      d = mydict(bob='239-8402', ted='371-8567', carol='891-5810',
> alice='552-2219')
> 
>      print('Using format():')
>      print('Email: {0:{{k}}: {{v}}}'.format(d))
>      print()
>      print('Using f-string:')
>      print(f'Email: {d:{{k}} {{v}}}')
>      print()
>      print('Using f-string:')
>      print(f'Email: {d:{{k}} {{v}}}', k=6, v=9)
> 
> 
> It generates the following response:
> 
>      Using format():
>      Template: {k}: {v}
>      Email: bob: 239-8402, ted: 371-8567, carol: 891-5810, alice: 552-2219
> 
>      Using f-string:
>      Traceback (most recent call last):
>      File "tryit", line 18, in <module>
>          print(f'Email: {d:{{k}} {{v}}}')
>      NameError: name 'k' is not defined

This is what I expected.

> Essentially I am using a format string as the template that indicates
> how to format each member of a dictionary, {{k}} should interpolate the
> key and {{v}} interpolates the value.  This format string is embedded
> inside another format string, so the braces are doubled up so that they
> will be ignored by the outer format string.

"The parts of the string outside curly braces are treated literally, 
except that any doubled curly braces '{{' or '}}' are replaced with the 
corresponding single curly brace. " note 'outside'

> This idea seems to work okay when using the format() method. You can see
> I added a print statement inside __format__ that shows that the method
> is being called.
> 
> However, trying the same idea with f-strings results in a NameError.  It
> appears that the escaping does not work when used within the template.
> It appears the error occurs before __format__ is called (there is no
> output from the print function).
> 
> Does anybody know why the format() method would work in this case but
> the f-string would not?

All names in the expression are resolved in the local namespace of the f 
string.  There are other differences.  Nesting can only be one level deep.

> Is this a bug in f-strings?

Not to me.


-- 
Terry Jan Reedy




More information about the Python-list mailing list