13

I'd like to use Python f-string for its syntactical simplicity, compared to string.Template() or other approach. However, in my application, the string is loaded from file, and the values of the variable can only be provided later.

If there a way to invoke fstring functionality separate from the string definition? Hopefully code below will better explain what I hope to achieve.

a = 5
s1 = f'a is {a}' # prints 'a is 5'

a = 5
s2 = 'a is {a}'
func(s2) # what should be func equivalent to fstring
Christopher Bottoms
  • 11,218
  • 8
  • 50
  • 99
idazuwaika
  • 2,749
  • 7
  • 38
  • 46

6 Answers6

5

By using eval() and passing either locals() or any arbitrary dict as the second positional locals argument, you can calculate an f-string dynamically on the fly with any combination of inputs.

def fstr(fstring_text, locals, globals=None):
    """
    Dynamically evaluate the provided fstring_text
    """
    locals = locals or {}
    globals = globals or {}
    ret_val = eval(f'f"{fstring_text}"', locals, globals)
    return ret_val

Sample usage:

format_str = "{i}*{i}={i*i}"
i = 2
fstr(format_str, locals()) # "2*2=4"
i = 4
fstr(format_str, locals()) # "4*4=16"
fstr(format_str, {"i": 12}) # "10*10=100"
aaronsteers
  • 2,277
  • 2
  • 21
  • 38
3

Use str.format().

Preferably, be explicit about passing arguments to it. But as a stopgap measure, you can use locals() to pass a dict of local (function-defined) variables to the formatting function:

foo = 'bar'
print('Foo is actually {foo}'.format(**locals()))

You can of course copy globals() to a local dict, and merge locals() to it, and use it to more closely emulate the f-string approach.

9000
  • 39,899
  • 9
  • 66
  • 104
  • 2
    This isn't equivalent, though may answer this user's question - `f'1+2 is {1=2}'` returns `'1+2 is 3'. See the answer relating to the string module below. – Steve Harris Feb 20 '19 at 08:39
  • 1
    @SteveHarris: Indeed, not equivalent! You likely don't want to evaluate expressions in strings loaded from a file when all you want is to pretty-print them. Evaluating untrusted input is a security hole. – 9000 Feb 22 '19 at 19:41
  • That's exactly what I was looking for when I found this question. The original equation was specifically about fstrings. – Steve Harris Feb 23 '19 at 20:03
1

you can format it this way. pass in a dictionary of possible values for a and map it to your string.

dictionary = {
  'a':[5,10,15]
}

def func(d):
  for i in range(3):
      print('a is {{a[{0}]}}'.format(i).format_map(d))

func(dictionary)

print:

a is 5
a is 10
a is 15
OLIVER.KOO
  • 5,654
  • 3
  • 30
  • 62
1

Here's what you were looking for:

pip install fstring

from fstring import fstring

x = 1

y = 2.0

plus_result = "3.0"

print fstring("{x}+{y}={plus_result}")

# Prints: 1+2.0=3.0
RinSlow
  • 119
  • 1
  • 3
0

Here you go:

In [58]: from functools import partial

In [59]: def func(var_name, a):
    ...:     return var_name + f' is {a}'
    ...:

In [60]: f = partial(func, 'a')

In [61]: f(5)
Out[61]: 'a is 5'
Amit Tripathi
  • 7,003
  • 6
  • 32
  • 58
0

I am surprised why nobody answered with lambda:

foobar = lambda x: f"Foobar is {x}"
foobar(5)
> "Foobar is 5"
Adam
  • 459
  • 2
  • 17