How to defer evaluation of f-strings

It seems that one solution is to use lambdas, which are explored below.

What other solutions are there?


Imagine that one wants to format a string selecting the format from several f-strings. Unfortunately, the obvious straightforward way of having the f-strings as values in a dictionary, does not work as desired, because the f-strings are evaluated when creating the dictionary. This unhappy way follows.


In [1]:
year, month, day = 'hello', -1, 0
date_formats = {
    'iso': f'{year}-{month:02d}-{day:02d}',
    'us': f'{month}/{day}/{year}',
    'other': f'{day} {month} {year}',
}

Notice below that the current values of year, month, and day are ignored when evaluating date_formats['iso'].


In [2]:
year, month, day = 2017, 3, 27
print(year, month, day)
print(date_formats['iso'])


2017 3 27
hello--1-0

A solution is to use lambdas in the dictionary, and call them later, as shown below.


In [3]:
year, month, day = 'hello', -1, 0
# year, month, and day do not have to be defined when creating dictionary.
del year  # Test that with one of them.
date_formats = {
    'iso': (lambda: f'{year}-{month:02d}-{day:02d}'),
    'us': (lambda: f'{month}/{day}/{year}'),
    'other': (lambda: f'{day}.{month}.{year}'),
}
dates = (
    (2017, 3, 27),
    (2017, 4, 24),
    (2017, 5, 22),
)

for format_name, format in date_formats.items():
    print(f'{format_name}:')
    for year, month, day in dates:
        print(format())


iso:
2017-03-27
2017-04-24
2017-05-22
us:
3/27/2017
4/24/2017
5/22/2017
other:
27.3.2017
24.4.2017
22.5.2017

This also answers the question about what good use there is for Zak K (aka y2kbugger)'s crazy whacko f-string lambdas. Thanks Zak!