4

Fairly often I use the string.format() for insertion of key-value pairs into a string template. The new Pep 498 f-strings have been recommended for a while but they seem to be a terrible choice for this behavior.

For instance if I wish to create a new f_string I need to make the variable first:

>>> date = 22
>>> date2 = f'this is a {date}'
>>> date2
'this is a 22'

Now if I try and perform the same action by creating an f-string template but without having the replacement value initialized I get the expected NameError

>>> date_template = f'this is a new {date_new}'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'date_new' is not defined

As there is no way to convert a string to f-string and f-strings appear to be mainly syntatic sugar. Is there a non-obvious way of using f-strings as templates or should I continue using string.format() and string.format_map()?

will.mont
  • 81
  • 5

1 Answers1

0

At the moment, there does not seem to be any better way than str.format and str.format_map.

After searching the Index of Python Enhancement Proposals, I found these two relevent PEPs: PEP 501 (General purpose string interpolation) and PEP 502 (String Interpolation - Extended Discussion). PEP 501 has been deferred with this note in the PEP document:

This PEP is currently deferred pending further experience with PEP 498's simpler approach of only supporting eager rendering without the additional complexity of also supporting deferred rendering.

I have not found any information about future plans regarding PEP 501.


There is a way to get around some of the limitations of locals() mentioned here.

In the following example, when f1 is called it throws a KeyError because locals() returns a dict with all the variables in the scope of f2, which does not contain x.

def f1():
    x = 4
    def f2():
        return 'x={x}'.format_map(locals())
    return f2()

When a variable defined in an outer scope is not used in a function, the interpreter will not waste resources including that variable in a closure. The interpreter cannot tell that x actually is used in f2 because that use is specified in the string, where the interpreter does not check for variable usage. Because x does not appear to be used in f2, it is discarded when f1 returns to save memory.

We can override this behavior by explicitly using x in f2.

def f1():
    x = 4
    def f2():
        x
        return 'x={x}'.format_map(locals())
    return f2()

Note: if x is already used in f2 there is no need to mention it again. For example:

def f1():
    x = 4
    def f2():
        print(x)
        return 'x={x}'.format_map(locals())
    return f2()

The (somewhat pointless) call to print here uses x so there is no need to explicitly use it anywhere else.

Community
  • 1
  • 1
TheGreatGeek
  • 56
  • 1
  • 2