f-strings 是 Python 3.6 引入的一種非常棒的字符串格式化方法。
相比其他格式方法,f-strings 更易讀、更簡潔、更少犯錯(cuò),也更快。
在了解為什么以及如何使用 f-strings 之前,我們先看一下在 f-strings 之前 Python 是如何進(jìn)行字符串格式化的。那是一段很艱難的日子,猶如大雪中艱難攀爬上下學(xué)路上的山坡。
【Python 中字符串格式的老式方法】
Python 3.6 之前,有兩種主要方式可將 Python 表達(dá)式嵌入到常量字符串中進(jìn)行格式化:% 格式化語法和 str.format() 方法。
我們來看一下這兩種方法的使用方法和局限之處。
1,% 格式化語法
這是 Python 中最古老的一種格式化方法,從一開始就存在于語言規(guī)范中。你可以在 Python 官方文檔中獲取更多相關(guān)信息。
你需要知道,官方文檔并不推薦 % 格式化方法,并給出如下理由:
那么,如何使用 % 格式化語法呢?
string 類型的對(duì)象支持使用 % 運(yùn)算符來執(zhí)行字符串格式化操作。
例如:
>>> name = 'Eric'
>>> 'Hello, %s' % name
'Hello, Eric'
如果要插入多個(gè)變量,你必須使用 tuple 來包含這些變量。
>>> name = 'Eric'
>>> age = 21
>>> 'Hello %s. You are %s.' % (name, age)
'Hello Eric. You are 21.'
上邊這兩段代碼可讀性還是不錯(cuò)的,但是,一旦你需要使用更多的變量和更長的格式字符串,代碼的可讀性就變得差很多了。
>>> first_name = 'Eric'
>>> last_name = 'Idle'
>>> age = 21
>>> profession = 'comedian'
>>> affiliation = 'Monty Python'
>>> "Hello, %s %s. You are %s. You are a %s. You were a member of %s." % (first_name, last_name, age, profession, affiliation)
'Hello, Eric Idle. You are 21. You are a comedian. You were a member of Monty Python.'
這段代碼開始顯得冗長,而且容易產(chǎn)生錯(cuò)誤:你可能在格式字符串中漏寫一個(gè) %,或者未能正確顯示 tuple 或 dict 對(duì)象。
幸運(yùn)的是,格式化之路前途光明。
2,str.format() 方法
這是 Python 2.6 引入的新式格式化方法,能勝任 % 完成的所有工作。
str.format() 是 % 格式化語法的一個(gè)改進(jìn)。它采用了正常的函數(shù)調(diào)用語法,并且可通過待格式化對(duì)象的 __format__() 方法進(jìn)行擴(kuò)展。
str.format() 在格式字符串中使用大括號(hào)為待格式化對(duì)象預(yù)留替換位。
>>> "Hello, {}. You are {}.".format(name, age)
'Hello, Eric. You are 21.'
可以通過變量在 str.format() 參數(shù)中的位置索引來引用這些對(duì)象。
>>> "Hello, {1}. You are {0}.".format(age, name)
'Hello, Eric. You are 21.'
也可以在格式字符串中插入變量名,這樣你就能夠傳遞對(duì)象,并在格式字符串的大括號(hào)里引用參數(shù)和方法。
>>> person = {'name': 'Eric', 'age': 21}
>>> "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age'])
'Hello, Eric. You are 21.'
>>> "Hello, {name}. You are {age}.".format(age=person['age'], name=person['name'])
'Hello, Eric. You are 21.'
>>>
>>> name = 'Eric'
>>> age = 21
>>> "Hello, {name1}. You are {age1}.".format(age1=age, name1=name)
'Hello, Eric. You are 21.'
對(duì)于字典(dict)類型的變量,也可以使用 ** 來實(shí)現(xiàn)這個(gè)操作:
>>> person = {'name': 'Eric', 'age': 21}
>>> "Hello, {name}. You are {age}.".format(**person)
str.format() 相比 % 格式化語法無疑是一個(gè)升級(jí),但難稱完美。
插入變量名使得它比 % 格式化語法更易讀;可在參數(shù)中對(duì)字典類型對(duì)象執(zhí)行解壓操作,使得代碼更簡潔。但是處理多個(gè)參數(shù)或較長字符串時(shí)同樣顯得冗長。
>>> first_name = "Eric"
>>> last_name = "Idle"
>>> age = 21
>>> profession = "comedian"
>>> affiliation = "Monty Python"
>>> "Hello, {first_name} {last_name}. You are {age}.You are a {profession}. You were a member of {affiliation}.".format(first_name=first_name, last_name=last_name, age=age, profession=profession, affiliation=affiliation)
'Hello, Eric Idle. You are 21.You are a comedian. You were a member of Monty Python.'
【f-strings:一種新的改進(jìn)的字符串格式化方法】
f-strings 是 Python 3.6 引入的一種新式字符串格式化方法,使得字符串格式化工作更簡單。
f-strings 也稱為格式化的字符串字面量,它以 f 開頭,在引號(hào)包含的字符串中使用大括號(hào)包含待求值的表達(dá)式。這些表達(dá)式在運(yùn)行時(shí)求值,然后通過 __format__ 協(xié)議實(shí)現(xiàn)格式化。
一起看一下 f-strings 是如何簡化格式化操作的吧。
1,簡單語法
f-strings 的基本語法和 str.format() 相似,但是更簡潔。
>>> name = 'Eric'
>>> age = 21
>>> f'hello, {name}. You are {age}.'
'hello, Eric. You are 21.'
只需直接寫一遍變量名即可。
也可以使用大寫的 F 作為前綴:
>>> F"Hello, {name}. You are {age}."
'Hello, Eric. You are 21.'
2,支持各種表達(dá)式
由于 f-strings 是在運(yùn)行時(shí)求值,你可以在其中放置任意合法的 Python 表達(dá)式,這讓你可以做一些很巧妙的事情。
你可以做一些很直接的事情:
>>> f'{2 * 37}'
'74'
也可以調(diào)用函數(shù):
>>> def to_lowercase(input):
... return input.lower()
...
>>> name = "Eric Idle"
>>> f"{to_lowercase(name)} is funny."
'eric idle is funny.'
還可以直接調(diào)用類方法:
>>> f"{name.lower()} is funny."
'eric idle is funny.'
你甚至可以在 f-strings 中格式化較復(fù)雜的對(duì)象,只要對(duì)象的類中恰當(dāng)運(yùn)用了 f-strings。
假設(shè)你有一個(gè)下邊這樣的類:
class Comedian:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
def __str__(self):
return f"{self.first_name} {self.last_name} is {self.age}."
def __repr__(self):
return f"{self.first_name} {self.last_name} is {self.age}. Surprise!"
你可以這樣直接格式化這個(gè)類的對(duì)象:
>>> new_comedian = Comedian("Eric", "Idle", "21")
>>> f"{new_comedian}"
'Eric Idle is 21.'
__str__() 和 __repr__() 方法用于處理對(duì)象如何表示為字符串,你至少應(yīng)該在類定義中包含其中一個(gè)方法。如果只定義一個(gè)的話,請(qǐng)使用 __repr__(),因?yàn)樗捎脕硖娲?__str__()。
__str__() 返回的字符串是一個(gè)對(duì)象的非正式字符串表示,應(yīng)該是可讀的。__repr__() 返回的字符串是正式的表示,應(yīng)該是明確的。
調(diào)用 str() 和 repr() 方法比直接使用 __str__() 和 __repr__() 要好。
默認(rèn)情況下,f-strings 會(huì)使用 __str__() 來輸出對(duì)象的字符串表示,但是如果你加入了轉(zhuǎn)換標(biāo)志 !r,f-strings 就會(huì)調(diào)用 __repr__()。
>>> f"{new_comedian}"
'Eric Idle is 21.'
>>> f"{new_comedian!r}"
'Eric Idle is 21. Surprise!'
3,多行 f-strings
你可以在 f-strings 中使用多行字符串。
>>> name = "Eric"
>>> profession = "comedian"
>>> affiliation = "Monty Python"
>>> message = (
... f"Hi {name}. "
... f"You are a {profession}. "
... f"You were in {affiliation}."
... )
>>> message
'Hi Eric. You are a comedian. You were in Monty Python.'
但是請(qǐng)注意,你需要在多行字符串的每一行之前放置 f 前綴。否則,格式化結(jié)果會(huì)出錯(cuò):
>>> message = (
... f"Hi {name}. "
... "You are a {profession}. "
... "You were in {affiliation}."
... )
>>> message
'Hi Eric. You are a {profession}. You were in {affiliation}.'
這段代碼只有第一個(gè)變量名被替換為實(shí)際值。
你也可以使用轉(zhuǎn)義符 \ 將 f-strings 擴(kuò)展到多行。
>>> message = f"Hi {name}. " \
... f"You are a {profession}. " \
... f"You were in {affiliation}."
>>>
>>> message
'Hi Eric. You are a comedian. You were in Monty Python.'
如果使用三引號(hào)字符串來定義多行 f-strings,輸出的格式化字符串也將是多行的。
>>> message = f"""
... Hi {name}.
... You are a {profession}.
... You were in {affiliation}.
... """
>>> message
'\n\tHi Eric. \n\tYou are a comedian. \n\tYou were in Monty Python.\n'
4,運(yùn)行速度
f-strings 中的 f 也可以代表 “fast”。通常情況下,f-strings 比 % 格式化語法和 str.format() 都要快。
如你所見,f-strings 實(shí)際上是一個(gè)運(yùn)行時(shí)求值的表達(dá)式,而不是常量值。
運(yùn)行時(shí),大括號(hào)中的表達(dá)式先在其自己的作用域中求值,然后和 f-strings 的字符串常量部分組合在一起,并返回結(jié)果字符串。這就是 f-strings 的全部工作。
這里給出一個(gè)比較三種格式化方式速度的例子。
>>> import timeit
>>> timeit.timeit("""name = "Eric"
... age = 74
... '%s is %s.' % (name, age)""", number = 10000)
0.003324444866599663
>>> timeit.timeit("""name = "Eric"
... age = 74
... '{} is {}.'.format(name, age)""", number = 10000)
0.004242089427570761
>>> timeit.timeit("""name = "Eric"
... age = 74
... f'{name} is {age}.'""", number = 10000)
0.0024820892040722242
可以看出,f-strings 速度較快。
但結(jié)果并非總是如此,不同版本的 Python 中,str.format() 有時(shí)候會(huì)快一些。
【f-strings 的一些語法細(xì)節(jié)】
我們已經(jīng)了解到 f-strings 擁有簡潔的語法和較快的速度,在開始使用 f-strings之前,再來了解幾點(diǎn)細(xì)節(jié)知識(shí)。
1,引號(hào)
在 f-strings 表達(dá)式中可以使用多種引號(hào),但是 f-strings 內(nèi)部表達(dá)式使用的引號(hào)和 f-strings 外部的引號(hào)不能相同。
下邊這兩種寫法都是正確的:
>>> f"{'Eric Idle'}"
'Eric Idle'
>>> f'{"Eric Idle"}'
'Eric Idle'
也可以使用三引號(hào):
>>> f"""Eric Idle"""
'Eric Idle'
>>> f'''Eric Idle'''
'Eric Idle'
如果你想在 f-strings 的內(nèi)部和外部使用相同的引號(hào),你需要使用轉(zhuǎn)義符 \ 來轉(zhuǎn)義內(nèi)部引號(hào):
>>> f"The \"comedian\" is {name}, aged {age}."
'The "comedian" is Eric, aged 21.'
2,字典變量
當(dāng)你打算在 f-strings 中插入字典變量的某些 key 時(shí),若你使用單引號(hào)引用 key 名,你需要在 f-strings 的外部使用雙引號(hào)。
>>> comedian = {'name': 'Eric Idle', 'age': 21}
>>> f"The comedian is {comedian['name']}, aged {comedian['age']}."
'The comedian is Eric Idle, aged 21.'
若你在 f-strings 的外部使用了和引用字典 key 相同的單引號(hào),Python 解釋器會(huì)報(bào)錯(cuò):
>>> comedian = {'name': 'Eric Idle', 'age': 21}
>>> f'The comedian is {comedian['name']}, aged {comedian['age']}.'
File "<stdin>", line 1
f'The comedian is {comedian['name']}, aged {comedian['age']}.'
^
SyntaxError: invalid syntax
所以,在 f-strings 中插入字典的 key 時(shí),需要特別留意引號(hào)的使用方法。
3,大括號(hào)
由于 f-strings 使用大括號(hào)來插入變量,如果想在 f-strings 中輸出 {} 字符,你需要使用雙重大括號(hào)。
>>> f"{{70 + 4}}"
'{70 + 4}'
但是,如果使用三重大括號(hào),格式化結(jié)果中只會(huì)保留一重大括號(hào):
>>> f"{{{70 + 4}}}"
'{74}'
如果使用超過三重的大括號(hào),你會(huì)在輸出中得到更多大括號(hào)。
>>> f"{{{{70 + 4}}}}"
'{{70 + 4}}'
>>> name = 'Eric'
>>> f"The \"comedian\" is {name}."
'The "comedian" is Eric.'
>>> f"{\"Eric\"}"
File "<stdin>", line 1
SyntaxError: f-string expression part cannot include a backslash
>>> f"Eric is {2 * 37 #Oh my!}."
File "<stdin>", line 1
SyntaxError: f-string expression part cannot include '#'
【結(jié)語】
f-strings 作為新式字符串格式化方法,在簡潔性、可讀性和運(yùn)行速度上都優(yōu)于其他方法,建議使用 Python 3.6 以上版本的小伙伴優(yōu)先采用此方法來格式化字符串。
聯(lián)系客服