盤一盤 Python 系列特別篇 - 格式化 String
- 2020 年 3 月 13 日
- 筆記
引言
格式化字元串(string formatting)是以指定輸出參數格式和相對位置來「美化」字元串。輸出參數格式包括數字的小數點位數、字元串大小寫等,相對位置標註出被格式化的詞是在句中的位置。比如
'It costs %.2f.' %(123.456)
其中 %.2f 是 123.456 的輸出參數格式,.2f 代表保留小數點兩位,而 %.2f 所在的位置在 costs 後面,意思說將 123.456 變成 123.46 後插在 costs 後面。
print('It costs %.2f.' %(123.456))It costs 123.46.
格式化字元串有四種方法:
- 用 % 字元 (上面用的)
- 用 $ 字元
- 用 format() 函數
- 用 f-string
本帖思路極其簡單
- 第一章先比較上述四種格式化方法,讓它們完成同樣的任務,誰好誰壞一目了然。
- 第二章選出兩個勝者,format() 函數和 f-string,對它們再做一個全方位的對比(),選出一個最後勝者 f-string。
- 第三章總結,用 f-string!用 f-string!用 f-string!
1、四種格式化方法
整帖中都以下面這句話舉例子,即「在 2020 年 3 月 4 日,阿里巴巴的市值為 553789 百萬美元」。
s = 'On 04 Mar 2020, the market cap of Alibaba is 553789 mio USD.' s
'On 04 Mar 2020, the market cap of Alibaba is 553789 mio USD.'
首先定義市值(Mcap)和貨幣單位(curr)兩個變數。
Mcap = 553789 curr = 'USD'
下面開始比較四種格式化的方法,用心去感受哪種最好。
用 % 字元格式化
'The market cap of Alibaba is %d mio %s.' %(Mcap, curr)
'The market cap of Alibaba is 553789 mio USD.'
該方法的核心範式是:

首先寫句子;再用 % 加小括弧,裡面列出要被格式化的變數名;最後在句子一一對應變數名的地方寫出 %x(d 代表數字,s 代表字元串,等等)。
照著上面具體例子品一遍,該方法不是很方便對吧。
用 $ 字元格式化
from string import Template info = dict(Mcap=Mcap, curr=curr) Template('The market cap of Alibaba is $Mcap mio $curr.') .substitute(info)'The market cap of Alibaba is 553789 mio USD.'
該方法的核心範式是:

在此方法下,我們需要將變數名和變數值作為鍵和值,創建一個字典。
首先要調用 Template 庫函數並將句子傳給它;再把字典傳入 substitute() 函數;最後在句子一一對應變數名的地方寫出 $k(k 代表字典中的鍵)。
照著上面具體例子品一遍,該方法也不是很方便對吧,而且還要引用額外的庫函數。
用 format 函數格式化
'The market cap of Alibaba is {} mio {}.'.format(Mcap, curr)'The market cap of Alibaba is 553789 mio USD.'
該方法的核心範式是:

首先寫句子;再用 format() 函數,裡面列出要被格式化的變數名;最後在句子一一對應變數名的地方只用寫出 {}。
照著上面具體例子品一遍,該方法還可以對吧,但還是有些冗長。
用 f-string 方法格式化
f'The market cap of Alibaba is {Mcap} mio {curr}.''The market cap of Alibaba is 553789 mio USD.'
該方法的核心範式是:

首先寫出句子,以 f' ' 或 F' ' 的形式;然後在句子只用寫出 {v},其中 v 是要被格式的變數。
照著上面具體例子品一遍,f-string 不能更方便是吧。很顯然它比其他三個用起來更簡單更自然,更強的是它還是最快的。
當決定用哪種格式化時,通常我們評估它是否簡單直觀而且符合自己的習慣,比如
- 那些有 C 語言背景的使用者就偏向用 「%」 字元
- 那些偏好標準化的使用者就偏向用 "$" 字元
- 那些偏好個性化的使用者就偏向用 format 函數
而我就喜歡 f-string 方法,下節就來比較 format 函數和 f-string 方法。我發現只要 format 函數能做到的,f-string 都能做到,而且程式碼寫出來更漂亮,運行更快,那為何不用呢?
2、Format Vs f-string
本節是兩強相爭,format() 函數和 f-string,它們兩個能做的事幾乎一樣,比如都能接收字典型數據、列表型數據、類數據;都能給數字型變數保留小數點,加分隔符;都能個性化日期型變數,等等。
字典型數據
創建字典。
info = dict(Mcap=Mcap, curr=curr) info
{'Mcap': 553789, 'curr': 'USD'}先看 format() 函數。
大括弧用 0 和 1 對應著 format() 函數中第 1 個和第 2 個參數。
'The market cap of Alibaba is {0} mio {1}.' .format(info['Mcap'], info['curr'])'The market cap of Alibaba is 553789 mio USD.'
這樣寫有些麻煩,format() 函數只傳進字典 info,而大括弧里的 0 就代表它,0[Mcap] 和 0[curr] 就是用鍵來獲取值。
'The market cap of Alibaba is {0[Mcap]} mio {0[curr]}.'.format(info)'The market cap of Alibaba is 553789 mio USD.'
我們來看看 f-string,怎麼出錯了???
f'The market cap of Alibaba is {info['Mcap']} mio {info['curr']}.'File "<ipython-input-26-1b50e8c7dcf6>", line 1 f'The market cap of Alibaba is {info['Mcap']} mio {info['curr']}.' ^ SyntaxError: invalid syntax因為一個完整的字元串句子是有前後單引號包住的,注意 f 後面有個單引號,而 info['Mcap'] 的前單引號被 Python 誤認為一連串字元串結束了。
怎麼辦呢?把 f-string 里的單引號改用雙引號就可以了。
f"The market cap of Alibaba is {info['Mcap']} mio {info['curr']}."'The market cap of Alibaba is 553789 mio USD.'
關鍵詞
創建字典,其鍵可當成關鍵詞(keyword)。
info = {'Mcap':Mcap, 'curr':curr} info{'Mcap': 553789, 'curr': 'USD'}先看 format() 函數。
用 ** 將字典打散傳入 format 就可以了。
'The market cap of Alibaba is {Mcap} mio {curr}.' .format(**info)'The market cap of Alibaba is 553789 mio USD.'
**info 和 format(info['Mcap'], info['curr']) 是一樣的。
列表型數據
創建列表。
info = [Mcap, curr] info
[553789, 'USD']
先看 format() 函數。
format() 函數只傳進列表 info,而大括弧里的 0 就代表它,0[0] 和 0[1] 就是用索引來獲取值。
'The market cap of Alibaba is {0[0]} mio {0[1]}.' .format(info)'The market cap of Alibaba is 553789 mio USD.'
再看 f-string,也是用索引來獲取列表 info 中的值,但是程式碼更簡潔。
f"The market cap of Alibaba is {info[0]} mio {info[1]}."'The market cap of Alibaba is 553789 mio USD.'
類數據
創建類 Info 並初始化一個對象 info。
class Info(): def __init__(self, Mcap, curr): self.Mcap = Mcap self.curr = curr
info = Info(Mcap, curr) info
<__main__.Info at 0x21113395048>
先看 format() 函數。
format() 函數只傳進對象 info,而大括弧里的 0 就代表它,0.Mcap 和 0.curr 就是用 info.method 的方式來獲取值。
'The market cap of Alibaba is {0.Mcap} mio {0.curr}.' .format(info)'The market cap of Alibaba is 553789 mio USD.'
再看 f-string,也是用 info.method 的方式來獲取列表 info 中的值,但是程式碼更簡潔。
f"The market cap of Alibaba is {info.Mcap} mio {info.curr}."'The market cap of Alibaba is 553789 mio USD.'
每三位數加逗號 ,
還是用字典作為輸入來舉例。
info = dict(Mcap=Mcap, curr=curr) info
{'Mcap': 553789, 'curr': 'USD'}一般在列印錢的數額時候,每三位需要一個逗號隔開而便於閱讀。
先看 format() 函數。
用 {0:,} 格式可以做到,重點是冒號和逗號。0 代表是 info[Mcap],即市值,是 553789。冒號後面跟著具體的格式,而逗號就是這個具體的格式。
'The market cap of Alibaba is {0:,} mio {1}.' .format(info['Mcap'], info['curr'])'The market cap of Alibaba is 553,789 mio USD.'
用 f-string 添加逗號的用法一樣,只不過程式碼簡潔些。
f"The market cap of Alibaba is {info['Mcap']:,} mio {info['curr']}."'The market cap of Alibaba is 553,789 mio USD.'
換算單位
現在加入我們想把百萬(mio)單位換算成十億(bio),需要在市值 553789 上除以 1000。
首先在字典中多添加一個鍵值對,unit:'bio'。
info = dict(Mcap=Mcap, curr=curr, unit='bio') info
{'Mcap': 553789, 'curr': 'USD', 'unit': 'bio'}接下來看 format() 函數和 f-string 的格式化用法,後者明顯簡潔。
'The market cap of Alibaba is {0:,} {1} {2}.' .format(info['Mcap']/1000, info['unit'], info['curr'])'The market cap of Alibaba is 553.789 bio USD.'
f"The market cap of Alibaba is {info['Mcap']/1000:,} {info['unit']} {info['curr']}."'The market cap of Alibaba is 553.789 bio USD.'
保留小數點位數
現在假如我們覺得小數點 3 位太多了,不要任何小數點。
先看 format() 函數。
用 {0:,.0f} 格式可以做到,冒號和逗號上面上面解釋過。.0f 代表小數點後面保留 0 位。
'The market cap of Alibaba is {0:,.0f} {1} {2}.' .format(info['Mcap']/1000, info['unit'], info['curr'])'The market cap of Alibaba is 554 bio USD.'
用 f-string 的用法一樣,只不過程式碼簡潔些。
f"The market cap of Alibaba is {info['Mcap']/1000:,.0f} {info['unit']} {info['curr']}."'The market cap of Alibaba is 554 bio USD.'
加入日期
首先引入 datetime,創建日期。
from datetime import datetimedate = datetime(2020, 3, 4)
在字典中增加一個鍵值對,date: datetime(2020, 3, 4)。
info = dict(date=date, Mcap=Mcap, curr=curr, unit='bio') info
{'date': datetime.datetime(2020, 3, 4, 0, 0), 'Mcap': 553789, 'curr': 'USD', 'unit': 'bio'}接下來比較 format() 函數和 f-string,後者明顯簡潔。
'On {3}, the market cap of Alibaba is {0:,.0f} {1} {2}.' .format(info['Mcap']/1000, info['unit'], info['curr'], info['date'])'On 2020-03-04 00:00:00, the market cap of Alibaba is 554 bio USD.'
f"On {info['date']}, the market cap of Alibaba is {info['Mcap']/1000:,.0f} {info['unit']} {info['curr']}."'On 2020-03-04 00:00:00, the market cap of Alibaba is 554 bio USD.'
但日期格式太難看了,調整日期格式可參考 https://strftime.org/。
- %Y - 年的全稱 (如 2020)
- %b - 月份的簡稱 (如 Mar)
- %d - 天數 (如果是個位數用零填充,如 03)
- %a - 日期的簡稱 (Wed)
結果如下:
'On {3:%b %d, %Y (%a)}, the market cap of Alibaba is {0:,.0f} {1} {2}.' .format(info['Mcap']/1000, info['unit'], info['curr'], info['date'])'On Mar 04, 2020 (Wed), the market cap of Alibaba is 554 bio USD.'
f"On {info['date']:%b %d, %Y (%a)}, the market cap of Alibaba is {info['Mcap']/1000:,.0f} {info['unit']} {info['curr']}."'On Mar 04, 2020 (Wed), the market cap of Alibaba is 554 bio USD.'
3、總結
困死了,不想總結了。以後想格式化字元串用 f-string 就完事了。如果真嗷嗷想用別的那就看張圖吧。


