如何推迟/推迟对F线的评估?
我正在使用模板字符串生成一些文件,并且我喜欢为此目的而使用的新 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 字符串,但我不知道是否存在这样的事情。
有什么方法可以引入字符串并将其解释为 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}
I am using template strings to generate some files and I love the conciseness of the new f-strings for this purpose, for reducing my previous template code from something like this:
template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
print (template_a.format(**locals()))
Now I can do this, directly replacing variables:
names = ["foo", "bar"]
for name in names:
print (f"The current name is {name}")
However, sometimes it makes sense to have the template defined elsewhere — higher up in the code, or imported from a file or something. This means the template is a static string with formatting tags in it. Something would have to happen to the string to tell the interpreter to interpret the string as a new f-string, but I don't know if there is such a thing.
Is there any way to bring in a string and have it interpreted as an f-string to avoid using the .format(**locals())
call?
Ideally I want to be able to code like this... (where magic_fstring_function
is where the part I don't understand comes in):
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)
...with this desired output (without reading the file twice):
The current name is foo
The current name is bar
...but the actual output I get is:
The current name is {name}
The current name is {name}
See also: How can I use f-string with a variable, not with a string literal?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
将字符串评估为F弦(具有其完整功能)的简洁方法是使用以下功能:
然后您可以执行:
与许多其他建议的解决方案相反,您也可以做:
A concise way to have a string evaluated as an f-string (with its full capabilities) is using following function:
Then you can do:
And, in contrast to many other proposed solutions, you can also do:
这是一个完整的“理想2”。
它不是F弦,甚至都不使用F-strings,而是根据要求进行的。符合指定的语法。没有安全性头痛,因为我们不使用
eval()
。它使用一个小型类并实现
__ str __
,该>由打印自动调用。为了逃脱类的有限范围,我们使用Inspect
模块将一个帧抬起并查看呼叫者访问的变量。Here's a complete "Ideal 2".
It's not an f-string—it doesn't even use f-strings—but it does as requested. Syntax exactly as specified. No security headaches since we are not using
eval()
.It uses a little class and implements
__str__
which is automatically called by print. To escape the limited scope of the class we use theinspect
module to hop one frame up and see the variables the caller has access to.是的,这正是我们使用带有替换字段和
.format
的文字的原因,因此我们可以随时通过调用format 来替换字段就可以了。
,即前缀
f/F
。您可以将其包装在一个函数中并在调用时推迟评估,但这当然会产生额外的开销:打印出:
但感觉不对,并且受到您只能查看替换中的全局命名空间这一事实的限制。尝试在需要本地名称的情况下使用它将会惨败,除非将其作为参数传递给字符串(这完全超出了要点)。
除了函数(包括限制)之外,不,所以不妨坚持使用
.format
。Yes, that's exactly why we have literals with replacement fields and
.format
, so we can replace the fields whenever we like by callingformat
on it.That's the prefix
f/F
. You could wrap it in a function and postpone the evaluation during call time but of course that incurs extra overhead:Which prints out:
but feels wrong and is limited by the fact that you can only peek at the global namespace in your replacements. Trying to use it in a situation which requires local names will fail miserably unless passed to the string as arguments (which totally beats the point).
Other than a function (limitations included), nope, so might as well stick with
.format
.怎么样:
How about:
使用.format不是此问题的正确答案。 python f -string与str.format()模板非常不同...它们可以包含代码或其他昂贵的操作 - 因此需要延期。
这是延期记录器的示例。这使用了日志记录的正常序言,但然后添加新功能,仅当日志级别正确时,才能解释F弦。
这具有能够执行以下操作的优点:
log.fdebug(“ {obj.dump()}”)
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。IMHO:这应该是f-strings的默认操作,但是现在为时已晚。 F弦弦评估可以具有巨大的意外副作用,并且以递延方式发生这种情况将改变程序执行。
为了使F-string适当推迟,Python需要某种明确切换行为的方法。也许使用字母“ G”? ;)
已经指出,如果字符串转换器中有一个错误,则延期记录不应崩溃。以上解决方案也可以执行此操作,最后将更改为
以外:
,然后在其中粘贴log.exception
。Using .format is not a correct answer to this question. Python f-strings are very different from str.format() templates ... they can contain code or other expensive operations - hence the need for deferral.
Here's an example of a deferred logger. This uses the normal preamble of logging.getLogger, but then adds new functions that interpret the f-string only if the log level is correct.
This has the advantage of being able to do things like:
log.fdebug("{obj.dump()}")
.... without dumping the object unless debugging is enabled.IMHO: This should have been the default operation of f-strings, however now it's too late. F-string evaluation can have massive and unintended side-effects, and having that happen in a deferred manner will change program execution.
In order to make f-strings properly deferred, python would need some way of explicitly switching behavior. Maybe use the letter 'g'? ;)
It has been pointed out that deferred logging shouldn't crash if there's a bug in the string converter. The above solution can do this as well, change the
finally:
toexcept:
, and stick alog.exception
in there.F-string只是创建格式化字符串的一种更简洁的方法,用
.format(**名称)
用f
替换。如果您不希望以这样的方式对字符串进行评估,请不要使其成为F串。将其保存为普通字符串文字,然后在您要执行插值时,请在其稍后拨打格式
。当然,有一个
eval
的替代方案。template.txt
:代码:
但是,您要做的就是将
str.format
替换为eval
,这肯定不值得。只需继续使用格式
调用常规字符串即可。An f-string is simply a more concise way of creating a formatted string, replacing
.format(**names)
withf
. If you don't want a string to be immediately evaluated in such a manner, don't make it an f-string. Save it as an ordinary string literal, and then callformat
on it later when you want to perform the interpolation, as you have been doing.Of course, there is an alternative with
eval
.template.txt
:Code:
But then all you've managed to do is replace
str.format
witheval
, which is surely not worth it. Just keep using regular strings with aformat
call.您想要的似乎被视为 Python 增强。
同时 - 从链接的讨论来看 - 以下似乎是一个合理的解决方法,不需要使用
eval()
:输出:
What you want appears to be being considered as a Python enhancement.
Meanwhile — from the linked discussion — the following seems like it would be a reasonable workaround that doesn't require using
eval()
:Output:
或者也许不使用 f 字符串,只需格式:
在没有名称的版本中:
Or maybe do not use f-strings, just format:
In version without names:
灵感来自 kadee的答案,可以使用以下来定义延迟的f-string类。
这正是问题所要求的
inspired by the answer by kadee, the following can be used to define a deferred-f-string class.
which is exactly what the question asked for
这些答案中的大多数有时会给你一些行为类似于 f 字符串的东西,但在某些情况下它们都会出错。
pypi 上有一个包
f-yeah
可以完成这一切,只需要花费两个额外的字符! (完全披露,我是作者)f 字符串和格式调用之间有很多差异,这里是一个可能不完整的列表
f"The argument is {spam=}"
使用 eval 的建议将为您提供完整的 f 字符串格式支持,但它们不适用于所有字符串类型。
在某些情况下,此示例还会出现变量作用域错误。
Most of these answers will get you something that behaves sort of like f-strings some of the time, but they will all go wrong in some cases.
There is a package on pypi
f-yeah
that does all this, only costing you two extra characters! (full disclosure, I am the author)There are a lot of differences between f-strings and format calls, here is a probably incomplete list
f"The argument is {spam=}"
The suggestions to use eval will get you full f-string format support, but they don't work on all string types.
This example will also get variable scoping wrong in some cases.
为此,我更喜欢在lambda功能中使用FSTRING,例如:
to do that I prefer to use fstring inside a lambda function like:
关于使用
str.format()
的讨论很多,但是如前所述,它不允许在诸如算术或切片之类的F弦乐中允许的大多数表达式。使用eval()
显然也有缺点。我建议您研究一种模板语言,例如Jinja。对于我的用例,它运行良好。请参阅下面的示例,其中我已经用单个卷曲支撑覆盖了变量注释语法,以匹配F弦语法。我没有完全回顾F-strings和Jinja之间的差异。
结果
There's a lot of talk about using
str.format()
, but as noted it doesn't allow most of the expressions that are allowed in f-strings such as arithmetic or slices. Usingeval()
obviously also has it's downsides.I'd recommend looking into a templating language such as Jinja. For my use-case it works quite well. See the example below where I have overridden the variable annotation syntax with a single curly brace to match the f-string syntax. I didn't fully review the differences between f-strings and Jinja invoked like this.
results in
我发现这个问题很有趣,并写了我自己的 library 实现懒惰的F-strings。
安装它:
并使用:
此解决方案非常适合用于记录。阅读有关链接中文档中的功能和限制的更多信息。
I found this problem quite interesting and wrote my own library implementing lazy f-strings.
Install it:
And use:
This solution is well suited, for example, for logging. Read more about the features and limitations in the documentation at the link.
使用 f 字符串的建议。做出您的评价
模板发生的逻辑级别并将其作为生成器传递。
您可以使用 f 弦在您选择的任何点展开它
A suggestion that uses f-strings. Do your evaluation on the
logical level where the templating is occurring and pass it as a generator.
You can unwind it at whatever point you choose, using f-strings
您可以使用
.format
样式替换,并明确定义替换的变量名称:输出
You could use a
.format
styled replacement and explicitly define the replaced variable name:Output
我遇到了这个问题,这与我要做的事情类似,唯一的区别是我需要提早评估的F弦乐的变量的某些,然后将其他F串变量推迟到以后确定。
因此,要从原始示例中借用,这就是我将其删除的方式:
I came upon this question which was similar to something I was trying to do, the only difference is that I needed some of the variables for my f-string evaluated early and then defer other f-string variables to be determined later.
So to borrow from the original example, here's how I pulled it off: