簡體   English   中英

我可以將 Python 3.6 的格式化字符串文字 (f-strings) 導入到舊的 3.x、2.x Python 中嗎?

[英]Can I import Python's 3.6's formatted string literals (f-strings) into older 3.x, 2.x Python?

新的 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 ...變化,所以不會包含在from __future__ import ...調用中。 但是更改不是向后移植 (AFAIK) 我需要確保我用 f-strings 編寫的任何新代碼只能在 Python 3.6+ 上運行,這對很多項目來說都是一個交易破壞者。

future-fstrings為 Python 2.7 腳本帶來了 f-strings。 (我根據文檔假設 3.3-3.5。)

一旦你通過pip install future-fstrings pip install 它,你必須在你的代碼頂部放置一個特殊的行。 那一行是:

# -*- 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 中未導入或由evalexec (我不推薦后兩者!)。

所以是的,你是對的,如果你想支持多個 python 版本,你不能輕易使用它們。

這是我使用的:

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

它解壓 ( ** ) locals()返回的 dict,它將所有局部變量作為 dict {variable_name: value}

請注意,這不適用於在外部作用域中聲明的變量,除非您使用nonlocal (Python 3.0+) 將其導入本地作用域。

你也可以使用

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

在字符串中包含全局變量。

f 字符串是由解釋器在標記f前綴時創建的 - 僅該功能就會消除任何兼容性機會。

您最接近的鏡頭是使用關鍵字格式,例如

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

在兼容性要求終止時可以更容易地重構。

我剛剛為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()

使用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))

使用 dict() 保存名稱-值對

  • 除了本線程中其他地方提到的方法(例如format(**locals()) )之外,開發人員還可以創建一個或多個 Python 字典來保存名稱-值對。

  • 對於任何有經驗的 Python 開發人員來說,這都是一種顯而易見的方法,但很少有討論明確列舉這個選項,也許是因為它是如此明顯的方法。

  • 這種方法相對於不加區別地使用locals()可以說是有利的,特別是因為它不那么不加區別地使用。 它明確地使用一個或多個字典作為命名空間來與您的格式化字符串一起使用。

  • Python 3 還允許解壓多個字典(例如, .format(**dict1,**dict2,**dict3) ...在 python 2.7 中不起作用)

## init dict
  ddvars = dict()

  ## assign fixed values
  ddvars['firname']   =   'Huomer'
  ddvars['lasname']   =   'Huimpson'
  ddvars['age']       =   33
  pass

  ## assign computed values
  ddvars['comname']   =   '{firname} {lasname}'.format(**ddvars)
  ddvars['reprself']  =   repr(ddvars)
  ddvars['nextage']   =   ddvars['age'] + 1
  pass

  ## create and show a sample message
  mymessage = '''
  Hello {firname} {lasname}!
  Today you are {age} years old.
  On your next birthday you will be {nextage} years old!
  '''.format(**ddvars)

  print(mymessage)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM