我正在使用模板字符串来生成一些文件,我喜欢为此目的的新f字符串的简洁性,以减少我以前的模板代码:
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print (template_a.format(**locals()))
现在我可以这样做,直接替换变量:
names = ["foo", "bar"]
for name in names:
print (f"The current name is {name}")
但是,有时在其他地方定义模板是有意义的 - 在代码中更高,或从文件或其他东西导入。这意味着模板是一个带有格式标签的静态字符串。必须在字符串上发生一些事情,告诉解释器将字符串解释为新的字符串,但我不知道是否有这样的事情。
有没有办法引入字符串并将其解释为f字符串以避免使用.format(**locals())
调用?
理想情况下,我希望能够像这样编码......(其中magic_fstring_function
是我不理解的部分所在的地方):
template_a = f"The current name is {name}"
# OR [Ideal2] template_a = magic_fstring_function(open('template.txt').read())
names = ["foo", "bar"]
for name in names:
print (template_a)
...使用此期望的输出(不读取文件两次):
The current name is foo
The current name is bar
...但我得到的实际输出是:
The current name is {name}
The current name is {name}
答案 0 :(得分:12)
f-string只是创建格式化字符串的一种更简洁的方式,将.format(**names)
替换为f
。如果您不希望以这种方式立即评估字符串,请不要将其设为f字符串。将其保存为普通的字符串文字,然后在您想要执行插值时再调用format
,就像您一直在做的那样。
当然,还有eval
的替代方案。
template.txt
:
f'当前名称为{name}'
代码:
>>> template_a = open('template.txt').read()
>>> names = 'foo', 'bar'
>>> for name in names:
... print(eval(template_a))
...
The current name is foo
The current name is bar
但是,您所做的只是将str.format
替换为eval
,这肯定是不值得的。只需通过format
调用继续使用常规字符串。
答案 1 :(得分:11)
这是一个完整的“理想2”。
它不是f字符串,甚至不使用f字符串。但它按要求提供。完全按照指定的语法。因为我们没有使用eval,所以没有安全问题。
它使用一个小类并实现__str__
,它由print自动调用。为了逃避类的有限范围,我们使用inspect
模块向上跳一帧并查看调用者可以访问的变量。
import inspect
class magic_fstring_function:
def __init__(self, payload):
self.payload = payload
def __str__(self):
vars = inspect.currentframe().f_back.f_globals.copy()
vars.update(inspect.currentframe().f_back.f_locals)
return self.payload.format(**vars)
template = "The current name is {name}"
template_a = magic_fstring_function(template)
# use it inside a function to demonstrate it gets the scoping right
def new_scope():
names = ["foo", "bar"]
for name in names:
print(template_a)
new_scope()
# The current name is foo
# The current name is bar
答案 2 :(得分:6)
这意味着模板是一个带有格式标签的静态字符串
是的,这正是我们为什么会有包含替换字段和.format
的文字的原因,因此我们可以随时通过调用format
来替换这些字段。
必须在字符串上发生一些事情,告诉解释器将字符串解释为新的f-string
这是前缀f/F
。你可以把它包装在一个函数中,并在调用时间推迟评估,但当然会产生额外的开销:
template_a = lambda: f"The current name is {name}"
names = ["foo", "bar"]
for name in names:
print (template_a())
打印出来:
The current name is foo
The current name is bar
但感觉不对,并且受限于您只能查看替换中的全局命名空间这一事实。试图在需要本地名称的情况下使用它将失败,除非作为参数传递给字符串(完全胜过这一点)。
有没有办法引入字符串并将其解释为f字符串以避免使用
.format(**locals())
调用?
除了功能(包括限制),nope之外,还可以坚持使用.format
。
答案 3 :(得分:5)
一种将字符串评估为f字符串(具有完整功能)的简洁方法是使用以下函数:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
favorite
<div class="secim" secim="tasarim">
<div class="tasarim-icerik">
<tasarim class="secimler">TASARIM</tasarim>
<img src="img/tasarim.png">
</div>
</div>
<div class="secim" secim="oyun">
<div class="oyun-icerik">
<oyun class="secimler">OYUN</oyun>
<img src="img/oyun.png">
</div>
</div>
<div class="secim" secim="hepsi">
<div class="hepsi-icerik">
<hepsi class="secimler">HEPSİ</hepsi>
<img src="img/hepsi.png">
</div>
</div>
那么您可以做:
def fstr(template):
return eval(f"f'{template}'")
而且,与其他许多提议的解决方案相比,您也可以执行以下操作:
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print(fstr(template_a))
# The current name is foo
# The current name is bar
答案 4 :(得分:4)
您想要的东西似乎被视为Python enhancement。
同时-在链接的讨论中-以下似乎是一种合理的解决方法,不需要使用eval()
:
class FL:
def __init__(self, func):
self.func = func
def __str__(self):
return self.func()
template_a = FL(lambda: f"The current name, number is {name!r}, {number+1}")
names = "foo", "bar"
numbers = 40, 41
for name, number in zip(names, numbers):
print(template_a)
输出:
The current name, number is 'foo', 41
The current name, number is 'bar', 42
答案 5 :(得分:3)
或者也许不使用f-strings,只需格式化:
fun = "The curent name is {name}".format
names = ["foo", "bar"]
for name in names:
print(fun(name=name))
在没有名字的版本中:
fun = "The curent name is {}".format
names = ["foo", "bar"]
for name in names:
print(fun(name))
答案 6 :(得分:2)
怎么样:
s = 'Hi, {foo}!'
s
> 'Hi, {foo}!'
s.format(foo='Bar')
> 'Hi, Bar!'
答案 7 :(得分:1)
使用.format不是这个问题的正确答案。 Python f字符串与str.format()模板非常不同......它们可能包含代码或其他昂贵的操作 - 因此需要延迟。
这是一个延迟记录器的示例。这使用logging.getLogger的正常前导码,但是只有在日志级别正确时才添加解释f字符串的新函数。
log = logging.getLogger(__name__)
def __deferred_flog(log, fstr, level, *args):
if log.isEnabledFor(level):
import inspect
frame = inspect.currentframe().f_back.f_back
try:
fstr = 'f"' + fstr + '"'
log.log(level, eval(fstr, frame.f_globals, frame.f_locals))
finally:
del frame
log.fdebug = lambda fstr, *args: __deferred_flog(log, fstr, logging.DEBUG, *args)
log.finfo = lambda fstr, *args: __deferred_flog(log, fstr, logging.INFO, *args)
这样做的好处是能够执行以下操作:log.fdebug("{obj.dump()")
....而不会转储对象,除非启用调试。
答案 8 :(得分:1)
这些答案中的大多数都会让您在某些时候表现得有点像 f-strings,但在某些情况下它们都会出错。
pypi f-yeah
上有一个包可以完成所有这些,只需要你多花两个字符! (完全公开,我是作者)
from fyeah import f
print(f("""'{'"all" the quotes'}'"""))
f-strings 和 format 调用之间有很多区别,这里是一个可能不完整的列表
f"The argument is {spam=}"
使用 eval 的建议将为您提供完整的 f 字符串格式支持,但它们不适用于所有字符串类型。
def f_template(the_string):
return eval(f"f'{the_string}'")
print(f_template('some "quoted" string'))
print(f_template("some 'quoted' string"))
some "quoted" string
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f_template
File "<string>", line 1
f'some 'quoted' string'
^
SyntaxError: invalid syntax
这个例子在某些情况下也会导致变量范围错误。
答案 9 :(得分:0)
使用f字符串的建议。你的评价 模板发生的逻辑级别并将其作为生成器传递。 您可以使用f-strings
在您选择的任何位置展开它In [46]: names = (i for i in ('The CIO, Reed', 'The homeless guy, Arnot', 'The security guard Spencer'))
In [47]: po = (f'Strangely, {next(names)} has a nice {i}' for i in (" nice house", " fast car", " big boat"))
In [48]: while True:
...: try:
...: print(next(po))
...: except StopIteration:
...: break
...:
Strangely, The CIO, Reed has a nice nice house
Strangely, The homeless guy, Arnot has a nice fast car
Strangely, The security guard Spencer has a nice big boat
答案 10 :(得分:0)
受answer by kadee的启发,以下内容可用于定义deferred-f-string类。
class FStr:
def __init__(self, s):
self._s = s
def __str__(self):
return eval(f"f'{self._s}'")
def __repr__(self):
return self.__str__()
...
template_a = FStr('The current name is {name}')
names = ["foo", "bar"]
for name in names:
print (template_a)
这正是问题的要求