short form for string.format(…,**locals())

一世执手 提交于 2019-12-08 18:10:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!