I usually use the following pattern (as mentioned in this question):
a=1
s= "{a}".format(**locals())
I think it's a great way to write easily readable code.
Sometimes it's useful to "chain" string formats, in order to "modularize" the creation of complex strings:
a="1"
b="2"
c="{a}+{b}".format(**locals())
d="{c} is a sum".format(**locals())
#d=="1+2 is a sum"
Pretty soon, the code is pestered with X.format(**locals())
.
To solve this problem, I tried to create a lambda:
f= lambda x: x.format(**locals())
a="1"
b="2"
c= f("{a}+{b}")
d= f("{c} is a sum")
but this throws a KeyError, since locals()
are the lambda's locals.
I also tried to apply the format only on the last string:
a="1"
b="2"
c="{a}+{b}"
d="{c} is a sum".format(**locals())
#d=="{a}+{b} is a sum"
But this doesn't work, since python only formats once. Now, I could write a function that formats repeatedly until there's nothing more to do:
def my_format( string, vars ):
f= string.format(**vars)
return f if f==string else my_format(f, vars)
but I'm wondering: is there a better way to do this?
f = lambda x, l=locals(): x.format(**l)
appears to work...
and if you wanted a version that is a little more all-encompassing (and probably a lot slower):
fg = lambda x, l=locals(), g=globals(): x.format(**dict(g.items() + l.items()))
will find the symbols in either locals or globals.
If you only need to do this within the function scope as a local shortcut, the following will work:
def formatter(fmt, loc=locals()):
return fmt.format(**loc)
However, this will bind the value returned by locals()
at the time of function declaration, rather than execution, so it will not be updated as values change, nor will it be useful when called from any other scope.
If you want to get access to the calling method's locals
, you need to inspect
the call stack (http://docs.python.org/2/library/inspect.html)
import inspect
def formatter(fmt):
parent = inspect.stack()[1][0] # 1 = the previous frame context
# 0 = the frame object
return fmt.format(**parent.f_locals)
Note that this may not work for implementations of python that are not CPython.
Now you can do:
a = "1"
b = "2"
c = formatter("{a}+{b}")
d = formatter("{c} is a sum")
Starting with Python 3.6 the effect of **locals()
is already included in string#format
or rather "formatted string literals".
See also PEP 498 and Python 3.6 release notes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With