每个人都喜欢Python 3.6的新f字符串:
In [33]: foo = {'blah': 'bang'}
In [34]: bar = 'blah'
In [35]: f'{foo[bar]}'
Out[35]: 'bang'
然而,虽然在功能上非常相似,但它们与str.format()
的语义完全相同:
In [36]: '{foo[bar]}'.format(**locals())
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-36-b7ef5aead76c> in <module>()
----> 1 '{foo[bar]}'.format(**locals())
KeyError: 'bar'
特别是str.format()
handles getitem syntax very differently:
In [39]: '{foo[blah]}'.format(**locals())
Out[39]: 'bang'
鉴于能够处理完整的python表达式语法,f字符串很精彩,我很喜欢它们。但它们有一个障碍:它们会立即进行评估,而使用str.format()
我可以将其格式化为模板保存,并在不同的上下文中多次格式化。
那么,有没有一种方法可以将字符串保存为模板,并在以后使用f-string语义对其进行评估?除了定义一个函数? f字符串是否等同于str.format()
?
更新
所以,这里假设的界面为例:
In [40]: mystr = '{foo[bar]}'
In [41]: make_mine_fstring(mystr, foo=foo, bar=bar)
Out[41]: 'bang'
答案 0 :(得分:2)
简要回答:没有。
您可以阅读有关这些f字符串的PEP-498。它清楚地定义了它们的目的和概念:这些字符串是就地评估的。结果是通常的str
格式化内容。您不能将f字符串存储为模板,因为f字符串没有特殊对象。
PEP-498的“Differences between f-string and str.format expressions”部分也提到了您的具体示例。
因此,无论你做什么,你都要使用内联就地f字符串或旧s.format()
语法,行为不同。
如果要从文件中读取f-string并根据f-strings的语法对其进行评估,可以使用eval:
foo = {'blah': 'bang', 'bar': 'sorry'}
bar = 'blah'
tpl = '{foo[bar]}'
print(tpl)
print(tpl.format(**locals())) # sorry
print(eval(f'f{tpl!r}')) # bang
请注意我们如何首先使用f-string,但将tpl
转换为自己的 repr 以立即进行评估。通常,对于简单类型,eval(repr(val))
应返回val
。但我们不是只放repr(tpl)
(或{tpl!r}
),而是将常规字符串的 repr 转换为f字符串,然后对其进行评估。
答案 1 :(得分:1)
这是我能想到的最接近的方法,但是它仍然使用eval()
,并且没有被函数很好地封装(由于范围问题):
def fize(text):
return 'f' + repr(text)
eval(fize(...))
其工作原理如下:
a = 10
eval(fize('{a}² = {a ** 2}'))
# '10² = 100'
如前所述,尝试定义例如:
def fmt(text):
return eval('f' + repr(text))
通常不能很好地工作,例如:
# this does works
a = 10
fmt('{a}')
# 10
# this does NOT work
def func(a, b, text='{a}, {b}'):
return fmt(text)
func(1, 2)
# NameError: name 'a' is not defined
在以下情况下有效:
def func(a, b, text='{a}, {b}'):
return eval(fize(text))
func(1, 2)
# '1, 2'
( EDIT :关于fmt()
函数的更新)。