我知道像
f"Foo is {age} {units} old"
这样的格式化字符串字面值不是破坏性的更改,因此不会包含在from __future__ import ...
中。但是这个改变(据我所知)没有被回溯到较早版本,我需要确保我使用f-strings编写的任何新代码仅在Python 3.6+上运行,这对于许多项目来说是无法接受的。f"Foo is {age} {units} old"
这样的格式化字符串字面值不是破坏性的更改,因此不会包含在from __future__ import ...
中。但是这个改变(据我所知)没有被回溯到较早版本,我需要确保我使用f-strings编写的任何新代码仅在Python 3.6+上运行,这对于许多项目来说是无法接受的。future-fstrings 将 f-strings 带到 Python 2.7 脚本中。(根据文档,我假设还支持 3.3-3.5 版本。)
一旦通过 pip install future-fstrings
安装它,您需要在代码的顶部放置一个特殊的行。那行是:
# -*- coding: future_fstrings -*-
然后你可以在代码中使用格式化字符串字面值(f-strings):
# -*- coding: future_fstrings -*-
var = 'f-string'
print(f'hello world, this is an {var}')
不幸的是,如果你想使用它,你必须要求 Python 3.6+
版本,与矩阵乘法运算符 @
和 Python 3.5+
或者 yield from
(Python 3.4+
,我想) 相同。
这些对代码的解释方式进行了更改,因此在旧版本中导入时会引发 SyntaxErrors。 这意味着你需要将它们放在旧版本 Python 中没有导入它们的地方,或者通过 eval
或 exec
进行保护(我不建议使用后两种方法!)。
所以,是的,你说得对,如果你想支持多个 Python 版本,就不能轻松地使用它们。
这是我使用的:
text = "Foo is {age} {units} old".format(**locals())
它解压(**
)由locals()
返回的字典,其中包含您所有的本地变量作为一个字典{variable_name: value}
注意: 这对于在外部作用域中声明的变量将不起作用,除非您使用nonlocal
将其导入到本地作用域中(仅适用于Python 3.0+)。
您还可以使用
text.format(**locals(),**globals())
在字符串中包含全局变量。
在解析 f
前缀时,解释器会创建 f-strings - 这个特性单独就足以导致不兼容。
你最接近的选择是使用关键字格式化,例如
'Foo is {age} {units} old'.format(age=age, units=units)
如果不再需要兼容性,就可以更轻松地重构它。
'Foo is {age} {units} old'.format(age=age, units=units)
,这样在转移到Python3.6时可以快速更新为f'Foo is {age} {units} old'
。 - petiepooo'Foo is {age} {units} old'.format(**locals(), **globals())
这个怎么样? - Mad Physicist我刚刚为f-string编写了一个回溯编译器,名为f2format
。就像您的要求一样,您可以在Python 3.6中编写f-string文字,并将其编译成兼容版本供最终用户运行,就像JavaScript的Babel
一样。
f2format
提供了一个智能但不完美的回溯编译器解决方案。它将使用str.format
方法替换f-string文字,同时保持源代码的原始布局。您只需使用
f2format /path/to/the/file_or_directory
即可原地重写所有Python文件。例如,
var = f'foo{(1+2)*3:>5}bar{"a", "b"!r}boo'
将被转换为
var = ('foo{:>5}bar{!r}boo').format(((1+2)*3), ("a", "b"))字符串拼接、转换、格式规范、多行和Unicode都被正确处理。此外,f2format
会在出现任何语法违规时存档原始文件。
我之前一直在使用'str'.format(**locals())
,但是后来觉得每个语句都需要额外的代码有点繁琐,于是写了这个。
def f(string):
"""
Poor man's f-string for older python versions
"""
import inspect
frame = inspect.currentframe().f_back
v = dict(**frame.f_globals)
v.update(**frame.f_locals)
return string.format(string, **v)
# Example
GLOBAL = 123
def main():
foo = 'foo'
bar = 'bar'
print(f('{foo} != {bar} - global is {GLOBAL}'))
if __name__ == '__main__':
main()
inspect
模块。 - ibonyun除了在本主题中提到的方法(如format(**locals())
),开发人员可以创建一个或多个Python字典来保存名称-值对。
对于有经验的Python开发人员来说,这是一种显而易见的方法,但很少有讨论明确列举这个选项,可能是因为它是如此显而易见。
相对于不加选择地使用locals()
,这种方法可以说是更有优势的。它明确地使用一个或多个字典作为命名空间与您的格式化字符串一起使用。
Python 3还允许解包多个字典(例如,.format(**dict1,**dict2,**dict3)
...这在Python 2.7中不起作用)
## 初始化字典 ddvars = dict()
## 分配固定的值 ddvars ['firname'] = 'Huomer' ddvars ['lasname'] = 'Huimpson' ddvars ['age'] = 33 pass
## 分配计算出来的值 ddvars ['comname'] = '{firname} {lasname}'.format(**ddvars) ddvars ['reprself'] = repr (ddvars) ddvars ['nextage'] = ddvars ['age'] + 1 pass
## 创建并显示一个示例消息 mymessage = ''' 你好 {firname} {lasname}! 今天你 {age} 岁了。 在你下一个生日时,你将 {nextage} 岁了! '''.format (**ddvars)
print(mymessage)
使用 simpleeval
的一种不太优秀的解决方案
import re
import simpleeval
test='_someString'
lst = ['_456']
s = '123123{lst[0]}{test}'
def template__format(template, context=None):
if context is None:
frame = inspect.currentframe()
context = frame.f_back.f_locals
del frame
ptn = '([^{]?){([^}]+)}'
class counter():
i = -1
def count(m):
counter.i += 1
return m.expand('\\1{%d}'%counter.i)
template = re.sub(ptn,string=s, repl= count)
exprs = [x[1] for x in re.findall(ptn,s)]
vals = map(simpleeval.SimpleEval(names=context).eval,exprs)
res = template.format(*vals)
return res
print (template__format(s))
Warning (mule): Invalid coding system
future_fstrings' is specified`。 - Muposat-*-
位,Python仍然能够识别它。 - Muposatimport future_fstrings future_fstrings.register()
- lytseeker