问题
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?
回答1:
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.
回答2:
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")
回答3:
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.
回答4:
It's not a one-liner, but it works:
def fmt(s, l=locals()):
while '{' in s:
s = s.format(**l)
return s
a="1"
b="2"
c="{a}+{b}"
d="{c} is a sum"
print fmt(d) # 1+2 is a sum
Here's a one line (and slightly less efficient) recursive version:
fmt = lambda s, l=locals(): fmt(s.format(**l), l=l) if '{' in s else s
来源:https://stackoverflow.com/questions/19549980/short-form-for-string-format-locals