54

对我来说,新的 Python 3.6 f-strings 似乎是字符串可用性的巨大飞跃,我很想在可能在旧解释器上运行的新项目中全心全意地采用它们。2.7、3.3-3.5 支持会很好,但至少我想在 Python 3.5 代码库中使用这些。如何导入 3.6 的格式化字符串文字以供较旧的解释器使用?

我知道格式化的字符串文字f"Foo is {age} {units} old"不会破坏性更改,因此不会包含在from __future__ import ...调用中。但是更改没有向后移植(AFAIK),我需要确保我用 f-strings 编写的任何新代码都只能在 Python 3.6+ 上运行,这对于很多项目来说都是一个交易破坏者。

4

8 回答 8

43

future-fstrings为 Python 2.7 脚本带来了 f-strings。(我根据文档假设 3.3-3.5。)

一旦你通过 pip install pip install future-fstrings,你必须在你的代码顶部放置一个特殊的行。那条线是:

# -*- coding: future_fstrings -*-

然后,您可以在代码中使用格式化的字符串文字(f-strings):

# -*- coding: future_fstrings -*-
var = 'f-string'
print(f'hello world, this is an {var}')
于 2017-09-12T17:12:14.343 回答
18

不幸的是,如果你想使用它,你必须要求Python 3.6+,与矩阵乘法运算符@Python 3.5+yield fromPython 3.4+我认为)相同

这些更改了代码的解释方式,因此在旧版本中导入时会引发 SyntaxErrors。这意味着您需要将它们放在旧 Python 中没有导入它们或由 or 保护的地方evalexec我不推荐后两者!)。

所以是的,你是对的,如果你想支持多个 python 版本,你不能轻易使用它们。

于 2017-02-07T18:20:24.390 回答
14

这是我使用的:

text = "Foo is {age} {units} old".format(**locals())

它解包(**)返回的字典,locals()其中包含所有局部变量作为字典{variable_name: value}

请注意,这不适用于在外部范围中声明的变量,除非您使用nonlocal(Python 3.0+) 将其导入本地范围。

你也可以使用

text.format(**locals(),**globals())

在您的字符串中包含全局变量。

于 2018-06-18T19:45:51.227 回答
7

f 字符串由解释器在标记f前缀时创建 - 仅该功能就会杀死任何兼容性机会。

您最接近的方法是使用关键字格式,例如

'Foo is {age} {units} old'.format(age=age, units=units)

在兼容性要求终止时可以更容易地重构。

于 2017-02-07T18:21:38.123 回答
4

我刚刚为f-string编写了一个反向端口编译器,称为f2format. 正如您所要求的,您可以使用Python 3.6风格编写f-string文字,并编译为最终用户可以运行的兼容版本,就像JavaScript 一样。Babel

f2format提供了一个智能但不完善的反向移植编译器解决方案。它将用方法替换f 字符串文字str.format,同时保持源代码的原始布局。你可以简单地使用

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将存档原始文件以防出现任何语法违规。

于 2018-09-16T15:25:47.793 回答
1

我已经使用'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()
于 2019-11-05T10:13:26.417 回答
0

使用 dict() 保存名称-值对

  • 除了这个线程中其他地方提到的方法(例如format(**locals()))之外,开发人员还可以创建一个或多个 python 字典来保存名称-值对。

  • 对于任何有经验的 python 开发人员来说,这是一个显而易见的方法,但很少有讨论明确列举这个选项,也许是因为它是如此明显的方法。

  • 相对于不分青红皂白的使用,这种方法可以说是有利的,locals()因为它不那么不分青红皂白。它明确使用一个或多个字典命名空间来与您的格式化字符串一起使用。

  • Python 3 还允许解包多个字典(例如,.format(**dict1,**dict2,**dict3)...在 python 2.7 中不起作用)

  ## 初始化字典
  ddvars = dict()

  ##分配固定值
  ddvars['firname'] = 'Huomer'
  ddvars['lasname'] = 'Huimpson'
  ddvars['年龄'] = 33
  经过

  ## 分配计算值
  ddvars['comname'] = '{firname} {lasname}'.format(**ddvars)
  ddvars['reprself'] = repr(ddvars)
  ddvars['nextage'] = ddvars['age'] + 1
  经过

  ## 创建并显示示例消息
  我的消息 = '''
  你好 {firname} {lasname}!
  今天你 {age} 岁。
  在您的下一个生日,您将满 {nextage} 岁!
  '''.format(**ddvars)

  打印(我的消息)
于 2019-12-13T18:55:02.387 回答
0

使用肮脏的解决方案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))

于 2019-05-28T16:19:20.450 回答