【问题标题】:short form for string.format(...,**locals())string.format(...,**locals()) 的缩写形式
【发布时间】:2013-10-23 18:50:07
【问题描述】:

我通常使用以下模式(如this question 中提到的):

a=1
s= "{a}".format(**locals())

我认为这是编写易于阅读的代码的好方法。

有时“链接”字符串格式很有用,以便“模块化”创建复杂字符串:

a="1"
b="2"
c="{a}+{b}".format(**locals())
d="{c} is a sum".format(**locals())
#d=="1+2 is a sum"

很快,代码就会被X.format(**locals()) 纠缠。 为了解决这个问题,我尝试创建一个 lambda:

f= lambda x: x.format(**locals())
a="1"
b="2"
c= f("{a}+{b}")
d= f("{c} is a sum")

但这会引发 KeyError,因为 locals() 是 lambda 的本地变量。

我还尝试仅在最后一个字符串上应用格式:

a="1"
b="2"
c="{a}+{b}"
d="{c} is a sum".format(**locals())
#d=="{a}+{b} is a sum"

但这不起作用,因为 python 只格式化一次。 现在,我可以编写一个重复格式化的函数,直到无事可做:

def my_format( string, vars ):
    f= string.format(**vars)
    return f if f==string else my_format(f, vars)

但我想知道:有没有更好的方法来做到这一点?

【问题讨论】:

    标签: python string lambda scope string-formatting


    【解决方案1】:

    f = lambda x, l=locals(): x.format(**l) 似乎可以工作......

    如果您想要一个更全面的版本(并且可能会慢很多):

    fg = lambda x, l=locals(), g=globals(): x.format(**dict(g.items() + l.items()))
    

    将在局部变量或全局变量中找到符号。

    【讨论】:

    • 您可能希望本地人覆盖全局变量。目前,你有相反的方式,因为后来的论点 dict 赢了。
    【解决方案2】:

    如果您只需要在函数范围内作为本地快捷方式执行此操作,则可以使用以下方法:

    def formatter(fmt, loc=locals()):
        return fmt.format(**loc)
    

    但是,这将绑定locals()在函数声明时返回的值,而不是执行,因此它不会随着值的变化而更新,也不会在从任何其他范围调用时有用。

    如果要访问调用方法的locals,需要inspect调用栈(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)
    

    请注意,这可能不适用于非 CPython 的 python 实现。

    现在你可以这样做了:

    a = "1"
    b = "2"
    c = formatter("{a}+{b}")
    d = formatter("{c} is a sum")
    

    【讨论】:

    • 实际上,有时确实如此,但并非总是如此……看起来 locals() 实际上返回了一个指向 'locals' 的 dict 值的指针,这似乎发生了变化。您可以进行以下实验:f = locals(); x = 1; g = locals(); f == g,即使您修改了 f 和 g 之间的局部值,这也是 True。另外:def fn(x, l=locals()): print l[x]; x = 2; fn('x'); x = 3; fn('x') 会先打印 2,然后再打印 3。有时它似乎应该是真的,所以这是一个很好的评论,但似乎有很多实际情况可以忽略它。
    【解决方案3】:

    从 Python 3.6 开始,**locals() 的效果已经包含在 string#format 或者更确切地说是“格式化字符串文字”中。

    另见PEP 498Python 3.6 release notes

    【讨论】:

      【解决方案4】:

      它不是单行的,但它有效:

      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
      

      这是一个单行(效率略低)的递归版本:

      fmt = lambda s, l=locals(): fmt(s.format(**l), l=l) if '{' in s else s
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-20
        • 2014-04-20
        • 1970-01-01
        • 1970-01-01
        • 2012-03-11
        • 1970-01-01
        • 2017-05-31
        相关资源
        最近更新 更多