2021年12月27日 星期一

Python 學習筆記 : 用 print() 函式輸出格式化字串

Python 的內建函式 print() 是最常用來輸出變數值的工具, 除了在開發過程中 debug 時用來檢視變數之值外, 也可以用在輸出報表時控制文字的輸出格式, 本篇對 Python 演化的過程中陸續發展出 % 運算子, format() 方法, 以及 f 字串這三種格式化字串輸出方式做了摘要整理與測試.    

參考文章 :   


參考書籍 : 

# 增壓的 Python (碁峰, 2020)
# Python 神乎其技 (全新超譯版, 旗標, 2020)
# Python 也可以這樣學 (博碩, 董付國, 2018)


Python 內建函式 print() 的語法如下 : 

print(value1, value2, .... [, sep=' ', end='\n'])

其中 value1, value2, ... 等參數為要輸出的變數或字面值 (literal), 亦即 print() 可以一次輸出多個值, 各個值以逗號隔開. 備選的關鍵字參數 sep 是用來隔開這些輸出資料的字串, 預設是一個空白字元; 而參數 end 是全部輸出結束時放在結尾的字串, 預設是換行字元 '\n', 故每次呼叫 print() 預設都會換行輸出, 若不要換行則需用 end 設定為其它字串, 例如 end 設為空字元會讓下一次 print() 的輸出緊接在此次 print() 輸出的後面. 

除了單純輸出資料外, print() 還可以控制輸出的格式, 在 Python 的發展過程中產生了三種格式化輸出方式, Python 2.x 使用 % 字元做為控制格式的運算子, Python 3 之後則在字串物件上新增了 format() 方法 (此方法後來也反向移植到 Python 2.7 裡), 而 Python 3.6 以後則新增了效率更好的 f 字串用法, 可以在字串中直接嵌入變數. 


1. 使用 % 運算子 : 

這是 Python 最早的字串格式化做法, 它是在字串中使用 % 運算子控制對應的變數在字串中的輸出格式, 其語法如下 : 

print("...%? .... %?" % (var1, var2, ...))     # 其中 %? 為格式化字串

print() 傳入參數分成三部分 : 




前面部分是內嵌格式化字串 %? 的輸出字串, 中間是 % 字元, 後面部分是要嵌入的變數序列元組 (對應前面的格式化字串), 變數數目需與前面輸出字串內的格式化字串 %? 數目一致, 輸出時將以對應之格式逐一插入字串中. 這三個部分可以連寫, 不需要用空格隔開, 但為了提高可讀性, 通常會用空格隔開. 如果只有一個變數要輸出, 則 tuple 的小括弧可以省略. 

% 格式化字元可控制變數輸出時的對齊方式, 正數是否冠 + 號, 空位是否補 0, 最小輸出長度, 以及精確度等, 語法如下 :

%[-][+][0][寬度][.精確度]型態

中括號表示可有可無, 說明如下 : 
  • - : 指定靠左對齊 (即寬度過多時預設為靠右對齊)
  • + : 正數前面加上 + 號
  • 0 : 寬度過多時空位補 0 (僅用於數值), 預設補空格
  • 寬度 : 指定最小輸出寬度 (超出時不受此限制)
  • 精確度 : 指定浮點數精確度到小數點後幾位或輸出字串中的前幾個字元
  • 型態 : 如 s (字串), d (整數), f (浮點數), e (科學表示法) 等
注意, 浮點數的寬度包含小數點, 資料寬度超過此指定寬度時不會被截斷 (因為這是最小寬度), 而是顯示完整的資料, 但變數值實際寬度小於此最小寬度設定時則會預設補空格 (數值可用 0 格式設為補 0). 資料寬度小於設定時也有對齊問題, 不論字串或數值在 % 格式化裡預設都是靠右對齊. 精確度雖然大部分用在浮點數或其科學表示法, 但也可用在字串, 表示輸出前幾個字元.  

另外, 寬度與精確度都可以用變數控制, 這時格式字元要用 * 字元代替明確之整數, 在 % 後面的 tuple 中, 必須在輸出資料的前面依序增加寬度與精確度之設定值 (可用變數), 如下圖所示 :



 
 控制資料型態的格式化字元如下表 :


 格式化字元 說明
 d 或 i 以整數格式輸出 (預設)
 f 或 F 以浮點數格式輸出數值
 s 以字串格式輸出任何資料型態之字串 (無引號)
 r 以字串格式輸出任何資料型態之字串 (有引號)
 c 輸出 0~127 整數所代表之 ASCII 字元
 x 以小寫之 16 進制格式 (0~9, a~f) 輸出整數
 X 以大寫之 16 進制格式 (0~9, A~F) 輸出整數
 o 以 8 進制整數格式 (0~7) 輸出整數
 e 以小寫 e 科學記號式輸出數值
 E 以大寫 E 科學記號式輸出數值
 g 以小寫 e 科學記號式輸出數值 (短格式)
 G 以大寫 E 科學記號式輸出數值 (短格式)
 % 輸出 % 字元


格式化輸出主要分為字串/字元與數值兩類, 其中最常用的是 %d (整數), %f (浮點數), 以及 %s (字串) 這三個, 例如 : 

>>> d=123                     # 整數
>>> f=3.14159               # 浮點數
>>> s='Hello World'     # 字串
>>> print('d=%d f=%f s=%s' % (d, f, s))     # 用適當的格式輸出    
d=123 f=3.141590 s=Hello World

如果只有一個資料要輸出, 變數可加或不加小括弧; 但兩個以上則必須加小括弧成為 tuple :

>>> print('d=%d' % d)          # 只輸出一個變數時可加或不加小括弧
d=123
>>> print('d=%d' % (d))       
d=123
>>> print('d=%d f=%f s=%s' % d, f, s)    # 輸出兩個以上變數時必須用 tuple 形式     
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: not enough arguments for format string     

變數通常應該使用適當的格式輸出 (數值用 %d, %f , %x 等, 字串用 %s), 但所有資料型態都可用 %s 字串格式輸出,  反之則不成立, 字串不可以用數值格式輸出, 例如 : 

>>> print('%s' % 123)                # 整數可用 %s 格式輸出
123
>>> print('%s' % 3.14159)         # 浮點數可用 %s 格式輸出
3.14159
>>> print('%s' % 3e-10)             # 浮點數可用 %s 格式輸出
3e-10
>>> print('%d' % '123')             # 字串不可用 %d 格式輸出
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: %d format: a number is required, not str
>>> print('%f' % '3.14159')       # 字串不可用 %f 格式輸出
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: must be real number, not str


(1). 輸出字串 : 

格式字元 s 或 r 可用來輸出字串, 兩者的差別是 %r 輸出的字串有引號, 而 %s 則沒有, 例如 :

>>> print('%s' % 'Hello World')    
Hello World
>>> print('%r' % 'Hello World')       
'Hello World'

這跟呼叫內建函式 str() 與 repr() 的效果類似, 呼叫後者會在傳入字串外再包一個雙引號 : 

>>> str('Hello')    
'Hello'
>>> repr('Hello')    
"'Hello'"  

關於 repr() 與 str() 參考 :


如果有指定寬度, 多出來的空位會補空格且預設向右對齊; 若要向左對齊可用 - 格式. 但實際字串大於指定寬度時會輸出完整字串, 而非截掉字串, 例如 : 

>>> print('|%10s' % 'Hello')             # 指定寬度 10, 預設向右對齊補空格
|     Hello
>>> print('%-10s|' % 'Hello')           # 指定寬度 10, 指定向左對齊預設補空格
Hello     |
>>> print('%5s' % 'Hello World')    # 字串長度超過指定時輸出完整字串
Hello World

字串也可以指定精確度, 它會控制要輸出字串中的前幾個字元, 例如 : 

>>> print('%.1s' % 'Hello')        # 輸出字串的前 1 個字元
H
>>> print('%.2s' % 'Hello')        # 輸出字串的前 2 個字元 
He
>>> print('%.3s' % 'Hello')        # 輸出字串的前 3 個字元
Hel
>>> print('%.4s' % 'Hello')        # 輸出字串的前 4 個字元
Hell
>>> print('%.5s' % 'Hello')        # 輸出字串的前 5 個字元
Hello
>>> print('%.6s' % 'Hello')        # 輸出字串的前 6 個字元
Hello

+ 格式只用在數值, 對字串無作用, 例如 : 

>>> print('%+s' % 'Hello')    
Hello

由於 % 被用來識別格式化字串的起點, 如果要輸出 % 本身必須用 %%, 例如 :

>>> print('%d%%' % (42))        # 輸出 % 字元本身
42%


(2). 輸出 ASCII 字元 : 

格式字元 c 可用來將 ASCII 碼 (0~127) 輸出為 ASCII 字元, 例如 : 

>>> print('%c' % 48)      # 輸出 ASCII 碼 48 的字元
0
>>> print('%c' % 57)      # 輸出 ASCII 碼 57 的字元
9
>>> print('%c' % 65)      # 輸出 ASCII 碼 65 的字元
A
>>> print('%c' % 90)      # 輸出 ASCII 碼 90 的字元
Z

這與內建函式 chr() 效果相同, 例如 :

>>> chr(48)          # 傳回 ASCII 碼 48 的字元
'0'
>>> chr(57)          # 傳回 ASCII 碼 57 的字元
'9'
>>> chr(65)          # 傳回 ASCII 碼 65 的字元
'A'
>>> chr(90)          # 傳回 ASCII 碼 90 的字元
'Z'

順帶一提, chr() 的反函數是 ord(), 它會傳回傳入字元之 ASCII 碼, 例如 : 

>>> ord('0')          # 傳回字元 0 的 ASCII 碼
48
>>> ord('9')          # 傳回字元 9 的 ASCII 碼
57
>>> ord('A')         # 傳回字元 A 的 ASCII 碼
65
>>> ord('Z')          # 傳回字元 Z 的 ASCII 碼
90


(3). 輸出整數 : 

輸出 10 進制整數可用 %d 格式, 輸出 8 進制整數使用 %o 格式, 輸出 16 進制整數則用 %x 格式 (小寫) 或 %X 格式 (大寫), 但就是缺了輸出二進制整數的格式 (沒有 %b 格式), 例如 : 

>>> print('%d' % 123)        # 10 進制
123
>>> print('%o' % 123)        # 8 進制
173
>>> print('%x' % 123)        # 16 進制 (小寫)
7b
>>> print('%X' % 123)       # 16 進制 (小寫)  
7B

不論哪個進制都可以配合使用 -, +, 0 等格式字元. 指定寬度格式時若整數小於此寬度時預設會向右靠齊, 並在前面空位補空格, 例如 : 

>>> print('|%10d' % 12345)         # 最小寬度 10, 預設靠右對齊補空格
|     12345
>>> print('|%010d' % 12345)       # 最小寬度 10, 預設靠右對齊補 0
|0000012345
>>> print('%-10d|' % 12345)        # 最小寬度 10, 指定靠左預設補空格
12345     |
>>> print('%-010d|' % 12345)      # 最小寬度 10, 指定靠左補 0 (無作用)
12345     |
>>> print('%3d' % 12345)            # 數值長度超過指定時輸出完整數值
12345

可見對整數而言, 指定靠左對齊時右方補 0 是沒作用的. 其它進制也是如此, 例如 16 進制 : 

>>> print('|%10x' % 56789)        # 16 進制預設靠右補空格
|      ddd5
>>> print('%010x|' % 56789)      # 16 進制預設靠右補 0
000000ddd5|
>>> print('%-10x|' % 56789)       # 16 進制指定靠左補空格
ddd5      |
>>> print('%3x' % 56789)           # 數值長度超過指定時輸出完整數值
ddd5
>>> print('%-010x|' % 56789)      # 最小寬度 10, 指定靠左補 0 (無作用)
ddd5      |

格式 + 會在正數前面添加 + 號 (0 算正數), 例如 : 

>>> print('%+d' % 12345)     # 正數會冠 +
+12345
>>> print('%+d' % 0)             # 0 被視為正數
+0
>>> print('%+d' % -12345)    # 負數不冠 +
-12345

指定精確度對整數沒甚麼意義, 但也不會報錯, 而是輸出完整的數字, 例如 :

>>> print('%.3d' % 12345)  
12345
>>> print('%.1d' % 12345)      
12345
>>> print('%2.1d' % 12345)     
12345

整數可以用 %e 或 %E 格式以科學表示法輸出, 也可以指定精確度, 例如 : 

>>> print('%e' % 12345)         # 預設顯示到小數第 6 位 (空位補 0)
1.234500e+04
>>> print('%E' % 12345)        # 預設顯示到小數第 6 位 (空位補 0)
1.234500E+04
>>> print('%.2e' % 12345)       # 顯示到小數 2 位 (四捨五入)
1.23e+04
>>> print('%.2E' % 12345)      # 顯示到小數 2 位 (四捨五入)
1.23E+04
>>> print('%e' % 1456789)      # 超出小數 6 位則完整輸出
1.456789e+06
>>> print('%.1e' % 1456789)    # 顯示到小數 1 位 (四捨五入)
1.5e+06
>>> print('%.1e' % 1446789)    # 顯示到小數 1 位 (四捨五入)   
1.4e+06

可見 e 或 E 格式預設會顯示到小數點後 6 位, 不足 6 位時空位補 0, 若指定精確度則四捨五入到指定之位數.  


(4). 輸出浮點數 :

輸出浮點數使用 %f 格式, 數值預設靠左顯示, 預設顯示到小數 6 位, 若小數部分有空位補 0 到 6 位, 超過則四捨五入到小數 6 位, 例如 : 

>>> print('圓周率=%f' % 3.14)                # 小數點後不足 6 位補 0 
圓周率=3.140000  
>>> print('圓周率=%f' % 3.14159)          # 小數點後不足 6 位補 0
圓周率=3.141590   
>>> print('圓周率=%f' % 3.1415926)      # 超過舊四捨五入到小數 6 位
圓周率=3.141593  

注意, 對浮點數指定寬度時是包含小數的. 指定精確度時會四捨五入到指定之小數位數; 指定 0 格式時空位會補 0 (預設補空格); 指定 + 格式時正數會顯示 + 號; 指定 - 格式會讓數值靠左對齊 (數值預設靠右對齊), 例如 : 

>>> print('圓周率=%12f' % 3.14159)         # 預設左方空位補空格
圓周率=    3.141590
>>> print('圓周率=%12.1f' % 3.14159)      # 指定顯示小數 1 位 (四捨五入)
圓周率=         3.1
>>> print('圓周率=%12.2f' % 3.14159)      # 指定顯示小數 2 位 (四捨五入)
圓周率=        3.14
>>> print('圓周率=%12.3f' % 3.14159)      # 指定顯示小數 3 位 (四捨五入)
圓周率=       3.142
>>> print('圓周率=%012.2f' % 3.14159)    # 指定左方空位補 0
圓周率=000000003.14
>>> print('圓周率=%+12f' % 3.14159)       # 正數顯示 +
圓周率=   +3.141590
>>> print('圓周率=%-12f' % 3.14159)        # 靠左對齊
圓周率=3.141590 

數值也可用 e 與 E 格式固定用科學表示法輸出, 預設顯示到小數點後 6 位, 過長截斷 (不是四捨五入), 空位則補 0. 指定精確度時會四捨五入到指定之小數位數, 指定寬度時寬度指的是從小數點後面起算的位數 (包含指數部分), 例如 : 

>>> print('%e' % 1.23456789)      # 預設顯示到小數點後 6 位 (截斷)
1.234568e+00
>>> print('%e' % 0.123456789)     
1.234568e-01
>>> print('%e' % 0.0123456789)     
1.234568e-02
>>> print('%+e' % 0.0123456789)      # 正數顯示 + 號
+1.234568e-02
>>> print('%.2e' % 0.0123456789)     # 指定精確度到小數後 2 位 (四捨五入)
1.23e-02
>>> print('%.3e' % 0.0123456789)     # 指定精確度到小數後 3 位 (四捨五入)
1.235e-02   
>>> print('%10e' % 0.0123)       # 指定小數點後 6 位 
1.230000e-02    

格式 g 與 G 會根據值的大小自動選擇用整數, 浮點數, 或科學表示法來輸出數值, 小數部分若與整數部分比起來小很多, 則小數部分會被捨棄. 指數超過 6 次方或小於 -5 次方時時會以科學表示法輸出 (相當於使用 e 或 E 格式), 在這範圍之內則用整數或浮點數輸出, 例如 : 

>>> print('%g' % 123456)                 # 用 g 格式輸出整數
123456
>>> print('%g' % 123456.789)          # 整數很大, 捨棄小數部分
123457
>>> print('%g' % 1234567)               # 寬度較長時自動改為科學表示法
1.23457e+06    
>>> print('%g' % 1234567.89)          # 寬度較長時自動改為科學表示法  
1.23457e+06
>>> print('%g' % 0.123456789)        
0.123457
>>> print('%g' % 0.0123456789)      
0.0123457
>>> print('%g' % 0.00123456789)      
0.00123457
>>> print('%g' % 0.000123456789)         
0.000123457
>>> print('%g' % 0.0000123456789)    # 指數小於 -4 時自動改為科學表示法 
1.23457e-05    
>>> print('%G' % 0.123456789)     
0.123457
>>> print('%G' % 0.0123456789)     
0.0123457
>>> print('%G' % 0.00123456789)    
0.00123457
>>> print('%G' % 0.000123456789)    
0.000123457
>>> print('%G' % 0.0000123456789)    # 寬度較長時自動改為科學表示法    
1.23457E-05  


(5). 可變寬度與精確度的用法 :

以上的範例中寬度與精確度格式均明確指定一個數值, 若用 * 字元取代明確的 m 與 .n則可以變數來控制這兩個格式, 這時後面的變數 tuple 中, 對應變數前面需傳入其寬度與精確度, 語法如下 (以輸出整數為例) : 

'%[+]*.*d' % (width, precision, variable)    

例如 :

>>> print('濕度 : %*d%%' % (5, 50))     
濕度 :    50%
>>> print('濕度 : %0*d%%' % (5, 50))         
濕度 : 00050%
>>> print('濕度 : %0*d%%' % (6, 50))       
濕度 : 000050%

注意, * 格式指的是寬度, 其值必須為整數, 下面是可變寬度的範例 :

>>> print('溫度 : %*.2f' % (6, 28.435))   
溫度 :  28.43
>>> print('溫度 : %0*.2f' % (6, 28.435))      
溫度 : 028.43
>>> print('溫度 : %0*.2f' % (7, 28.435))     
溫度 : 0028.43

下面是可變精確度範例 :

>>> print('溫度 : %6.*f' % (1, 28.435))    
溫度 :   28.4
>>> print('溫度 : %6.*f' % (2, 28.435))    
溫度 :  28.43
>>> print('溫度 : %6.*f' % (3, 28.435))    
溫度 : 28.435
>>> print('溫度 : %6.*f' % (4, 28.435))      
溫度 : 28.4350

下面是寬度與精確度同時可變的範例 : 

>>> print('溫度 : %*.*f' % (6, 1, 28.435))    
溫度 :   28.4
>>> print('溫度 : %*.*f' % (6, 2, 28.435))     
溫度 :  28.43
>>> print('溫度 : %*.*f' % (6, 3, 28.435))     
溫度 : 28.435
>>> print('溫度 : %0*.*f' % (7, 3, 28.435))      
溫度 : 028.435

輸出多個可變寬度格式的範例如下 : 

>>> print('溫度 : %0*.*f 濕度 : %0*d%%' % (6, 2, 28.435, 4, 50))    
溫度 : 028.43 濕度 : 0050%

注意, 使用 * 可變寬度與精確度格式時, 傳入的 tuple 元素要一一對應. 


2.  使用 format() 方法 :

此種方式是從 Python 3.0 開始支援的, 字串物件中多了一個 format() 方法來格式化要輸出的字串, 其語法除對應位置內嵌外, 還支援與位置無關的變數序號內嵌與關鍵字內嵌, 比傳統的 % 格式化更有彈性, 且繼承了 % 格式化字元用法 (除了對齊方式以外). 


(1). 對應位置內嵌 :    

此與傳統 % 格式化用法類似, 只不過把 % 換成 {} 而已, 語法如下 : 

print("...{}...{}...".format(var1, var2, ...))    

例如 : 

>>> name='Tony'       
>>> age=22   
>>> print("name:{} age:{}".format(name, age))    # 將變數輸出到對應之 {}    
name:Tony age:22       
>>> str="name:{} age:{}"        
>>> print(str.format(name, age))       
name:Tony age:22    

內嵌大括弧內可用冒號加上  <, ^, > , +, 0 等格式化字元對變數進行格式化, 語法如下 :

:[[填充]<|^|>|=][+][0][寬度][,][.精確度]型態
  • 填充 : 若資料寬度比指定最小寬度小時用來填充空位的字元
  • < : 靠左對齊
  • ^ : 置中對齊
  • > : 靠右對齊
  • = : 在 +/- 號與數值間用填充字元補位 (僅限數值)
  • + : 正數前面加上 + 號
  • 0 : 寬度過多時空位補 0 (用於數值)
  • 寬度 : 指定最小輸出寬度 (超出時不受此限制)
  • , : 千位符號, 將整數部分每千位打一個逗號
  • 精確度 : 指定浮點數精確度到小數點後幾位或輸出字串中的前幾個字元
  • 型態 : 與 % 格式化之型態相同 (例如 d, f, s 等), 另新增二進制類型 b
這些格式化字元必須放在一個冒號之後. 比較特殊的是, format() 有更豐富的對齊格式, 可靠左, 置中, 與靠右對齊, 而且可在前面設定填充字元, 其優先權比補 0 高. 注意, 填充字元需搭配對齊格式, 不可單獨使用. 其次, format() 增加了一個千位符號格式 (即逗號) 以及二進制整數型態 b. 另外, 由於 format() 使用了大括弧 {} 內嵌, 輸出大括弧本身要用 {{ 與 }}.

% 格式化的 s 類型可用來輸出字串或數值, 例如 :

>>> print('%s' % ('Hello'))       # s 型態本用來輸出字串
Hello
>>> print('%s' % (123))             # s 型態也可輸出數值 (整數)
123
>>> print('%s' % (3.14159))      # s 型態也可輸出數值 (浮點數)
3.14159
>>> print('%s' % (1.23e-9))       # s 型態也可輸出數值 (科學表示法)
1.23e-09

format() 格式化的 s 型態只能輸出字串, 不可用來輸出數值, 否則會報錯, 例如 : 

>>> print('{:s}'.format('Hello'))       # s 型態只能用來輸出字串
Hello
>>> print('{:s}'.format(123))            # s 型態不可用來輸出字數值
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'int'
>>> print('{:s}'.format(3.14159))     # s 型態不可用來輸出字數值
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'float'
>>> print('{:s}'.format(1.23e-9))      # s 型態不可用來輸出字數值
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
ValueError: Unknown format code 's' for object of type 'float'

當指定之寬度大於資料實際寬度時可設定對齊方式, format() 的對齊分別用 <, ^, 與 > 表示靠左, 置中, 與靠右對齊 (字串預設靠左, 數值預設靠右), 而傳統 % 格式化是預設靠右 (不論字串或數值預設皆靠右), 使用 - 字元控制靠左對齊 (無法置中), 所以 format() 的對其方式較有彈性, 例如 : 

>>> print('|{:10d}|'.format(123))           # 數值預設靠右對齊   
|       123|
>>> print('|{:<10d}|'.format(123))         # 指定靠左對齊
|123       |
>>> print('|{:^10d}|'.format(123))         # 指定置中對齊
|   123    |
>>> print('|{:>10d}|'.format(123))         # 指定靠右對齊
|       123|
>>> print('|{:10s}|'.format('Hello'))       # 字串預設靠左對齊   
|Hello     |
>>> print('|{:<10s}|'.format('Hello'))     # 指定靠左對齊
|Hello     |
>>> print('|{:^10s}|'.format('Hello'))     # 指定置中對齊 
|  Hello   |
>>> print('|{:>10s}|'.format('Hello'))     # 指定靠右對齊
|     Hello|

對齊格式前面可指定填充字元, 當資料寬度小於指定寬度時, 空位就會用此填充字元補滿, 其優先權高於後面的補 0 格式, 亦即, 若輸出數值時同時指定填充字元與補 0, 則補 0 會被忽略. 填充字元對於製作標題或分隔行很方便, 例如 : 

>>> print('{:=^20s}'.format('Hello World'))    # 置中對齊空位以 = 填充
====Hello World=====
>>> print('{:*^20s}'.format('Hello World'))    # 置中對齊空位以 * 填充
****Hello World*****
>>> print('{:=<20s}'.format('Hello World'))    # 靠左對齊空位以 = 填充
Hello World=========
>>> print('{:=>20s}'.format('Hello World'))    # 靠右對齊空位以 = 填充    
=========Hello World
>>> print('{:#^20d}'.format(123))       # 置中對齊空位以 # 填充 (輸出數值)
########123#########
>>> print('{:#^020d}'.format(123))     # 置中對齊空位以 # 填 (補 0 無效)
########123#########

對於數值資料而言, 可用 = 對齊格式設定在 +/- 號與數值之間的空位用填充字元補位, 例如 : 

>>> print('{:0=20d}'.format(123))           # 在 +/- 與數值間以 0 填充
00000000000000000123
>>> print('{:*=20d}'.format(123))           # 在 +/- 與數值間以 * 填充
*****************123
>>> print('{:=+20d}'.format(123))           # 在 +/- 與數值間以空格填充 (預設)
+                123
>>> print('{:0=+20d}'.format(123))         # 在 +/- 與數值間以 0 填充 (正數)
+0000000000000000123
>>> print('{:0=+20d}'.format(-123))        # 在 +/- 與數值間以 0 填充 (負數)
-0000000000000000123 

格式化字元 + 控制正數顯示 + 號, 例如 : 

>>> print('{}'.format(123))          # 預設正數不顯示 + 號
123
>>> print('{:+}'.format(123))      # 指定正數顯示 + 號
+123

format() 方法對於整數新增了二進制類型 b, 以補 % 格式化之缺陷, 例如 : 

>>> print('{:d}'.format(15))      # 輸出 10 進位整數 
15
>>> print('{:x}'.format(15))      # 輸出 16 進位整數 (小寫)
f
>>> print('{:X}'.format(15))     # 輸出 16 進位整數 (大寫)
F
>>> print('{:o}'.format(15))      # 輸出 8 進位整數
17
>>> print('{:b}'.format(15))      # 輸出 2 進位整數
1111
>>> print('{:b}'.format(123))    # 輸出 2 進位整數
1111011

若資料寬度小於指定之最小寬度, 預設空位補空格, 但數值可用 0 格式指定補 0. 字串也可以補 0, 雖然較少會用到, 例如 : 

>>> print('|{:^10d}|'.format(123))             # 預設空位補空格
|   123    |
>>> print('|{:^010d}|'.format(123))           # 指定空位補 0
|0001230000|
>>> print('|{:^010f}|'.format(123.45))       # 指定空位補 0 (浮點數補在小數)
|123.450000|
>>> print('|{:^010.2f}|'.format(123.45))    # 指定空位補 0 (浮點數整數小數均補 0)
|00123.4500|
>>> print('|{:^010s}|'.format('Hello'))   
|00Hello000|

此處特地用 "^" 讓資料置中對齊, 且前後插入 "|" 字元以便觀察空位之補位情形, 可見對於浮點數而言, 沒有指定小數位數時, 0 會全部補在小數尾端; 有指定精確度, 且有空位時, 整數與小數部分會平均補 0.  

format() 新增了千位符號格式, 其位置是在寬度格式後面, 例如 :

>>> print('{:,d}'.format(123456789))         
123,456,789
>>> print('|{:09,d}|'.format(123456789))       # 沒有超過千位不補 0
|123,456,789|
>>> print('|{:010,d}|'.format(123456789))      # 沒有超過千位不補 0
|123,456,789|
>>> print('|{:011,d}|'.format(123456789))      # 沒有超過千位不補 0
|123,456,789|
>>> print('|{:012,d}|'.format(123456789))      # 超過千位才會補 0
|0,123,456,789|

精確度主要是用在浮點數與科學表示法, 以四捨五入方式顯示到指定之小數位數. 精確度也可以用在字串, 這時會輸出字串的前幾個字元, 例如 : 

>>> print('圓周率={:.1f}'.format(3.1415926))    # 四捨五入到小數 1 位
圓周率=3.1
>>> print('圓周率={:.3f}'.format(3.1415926))    # 四捨五入到小數 3 位
圓周率=3.142
>>> print('{:.2e}'.format(0.123456789))              # 四捨五入到小數 2 位
1.23e-01
>>> print('{:.3e}'.format(0.123456789))              # 四捨五入到小數 3 位
1.235e-01
>>> print('{:.4e}'.format(0.123456789))              # 四捨五入到小數 4 位
1.2346e-01
>>> print('message={:.3s}'.format('Hello'))      # 輸出字串中的前 3 字元 
message=Hel
>>> print('message={:.7s}'.format('Hello'))      # 輸出字串中的前 7 字元
message=Hello

若要輸出大括號本身, 需使用 {{ 與 }}, 例如 :

>>> print('集合 s={{{0}}}, {{{1}}}, {{{2}}}'.format(1, 2, 3))      
集合 s={1}, {2}, {3}

此處 {{{0}}} 前面的 {{ 與後面的 }} 都是要輸出大括號本身 (集合符號), 中間的 {0} 才是內嵌要輸出的資料.  


(2). 序號內嵌 :  

除了上述對應位置內嵌外, 還可以在大括弧 {} 中填入序號 (0 起始) 來對應傳入 format() 之資料順序, 語法如下 :

print("...{1}...{0}...".format(ab, ...)) 

此處 a 會被嵌入後面的 {0}, 而 b 則會被嵌入前面的 {1}. 

格式化字串則依序放在冒號後面, 語法如下 :

print("...{0:格式化字串}...{1:格式化字串}...".format(ab, ...)) 

例如 : 

>>> temp=28.435   
>>> humid=50   
>>> print('溫度 : {0} 濕度 : {1}%'.format(temp, humid))   
溫度 : 28.435 濕度 : 50%
>>> print('濕度 : {1}% 溫度 : {0}'.format(temp, humid))      # 序號調換
濕度 : 50% 溫度 : 28.435
>>> print('溫度 : {0:07.2f} 濕度 : {1:04d}%'.format(temp, humid))     
溫度 : 0028.43 濕度 : 0050%
>>> print('溫度 : {0:+08.2f} 濕度 : {1:+06d}%'.format(temp, humid))    # 正數帶 + 號
溫度 : +0028.43 濕度 : +00050%   

若傳入 format() 的引數是串列或元組, 序號後面可用 [] 存取序列中的元素來內嵌, 例如 : 

>>> print('tuple : {0[0]}, {0[1]}, {0[2]}'.format((1, 2, 3)))   
tuple : 1, 2, 3
>>> print('list : {0[0]}, {0[1]}, {0[2]}'.format([1, 2, 3]))        
list : 1, 2, 3


(3). 關鍵字內嵌 :  

也可以直接在 {} 中直接指定關鍵字來內嵌該變數, 語法如下 : 

print("...{b}...{a}...".format(a=v1b=v2, ...)) 

這樣就不需要煩惱序號對應的問題了. 

格式化字串同樣放在冒號之後, 語法如下 :

print("...{b:格式化字串}...{a:格式化字串}...".format(a=v1b=v2, ...)) 

例如 : 

>>> temp=28.435   
>>> humid=50   
>>> print('溫度 : {temp} 濕度 : {humid}%'.format(temp=temp, humid=humid))     
溫度 : 28.435 濕度 : 50%
>>> print('溫度 : {temp:07.2f} 濕度 : {humid:04d}%'.format(temp=temp, humid=humid))   
溫度 : 0028.43 濕度 : 0050%

此種用法最有彈性, 但要注意 format() 裡面的傳入參數必須指定關鍵字, 不可只傳入變數, 否則會出現 KeyError 錯誤, 因為內嵌時找不到所需的關鍵字, 例如 :

>>> temp=28.435   
>>> humid=50   
>>> print('溫度 : {temp} 濕度 : {humid}%'.format(temp, humid))    
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
KeyError: 'temp'    

若傳入 format() 的引數是串列或元組, 關鍵字後面可用 [] 存取序列中的元素來內嵌, 例如 : 

>>> print('tuple : {a[0]}, {a[1]}, {a[2]}'.format(a=(1, 2, 3)))   
tuple : 1, 2, 3
>>> print('tuple : {a[0]}, {a[1]}, {a[2]}'.format(a=[1, 2, 3]))    
tuple : 1, 2, 3


3.  使用 f 字串 :

f 字串是字串前面冠上一個 f 的格式化字串, Python 自 3.6 版開始支援這種字串格式化方式, 它可以將變數或運算式直接用 {} 內嵌到 f 字串中, 比 format() 更好用, 語法如下 : 

print(f".....{var}.....{expression}.....")      

其中 var 為變數, expression 為運算式. 

Python 3.8 版又為 f 字串添加新功能, 在變數或運算式後面加一個 "=" 號將輸出變數名稱或運算式與等號, 這對程式偵錯相當方便, 語法如下 : 

print(f".....{var=}.....{expression=}.....")    

例如 : 

>>> pi=3.14159   
>>> r=5    
>>> print(f'半徑={r}, 圓周長={2*pi*r}, 圓面積={pi*r*r}')    
半徑=5, 圓周長=31.4159, 圓面積=78.53975   
>>> print(f'{r=}, {2*pi*r=}, {pi*r*r=}')   
r=5, 2*pi*r=31.4159, pi*r*r=78.53975

如果在 Python 3.8 之前的環境執行會出現語法錯誤, 例如 : 

>>> print(f'{r=}, {2*pi*r=}, {pi*r*r=}')    
  File "<fstring>", line 1
    (r=)
      ^
SyntaxError: invalid syntax

f 字串的格式化字元與前面 format() 中使用的完全一樣, 只要在變數或運算式後面加個冒號, 後面接著放置格式化字串即可, 語法如下 : 

print(f".....{var:格式化字串}.....{expression:格式化字串}.....")    

例如以 2, 8, 10, 16 進制輸出整數 : 

>>> print(f'{15:d}')         # 輸出 10 進位整數 (小寫)
15
>>> print(f'{15:x}')         # 輸出 16 進位整數 (小寫)
f
>>> print(f'{15:X}')        # 輸出 16 進位整數 (大寫)
F
>>> print(f'{15:o}')         # 輸出 8 進位整數
17
>>> print(f'{15:b}')         # 輸出 2 進位整數
1111

下面是空位補 0 的範例 :

>>> print(f'|{123:^10d}|')             # 預設空位補空格
|   123    |
>>> print(f'|{123:^010d}|')           # 指定空位補 0
|0001230000|
>>> print(f'|{123.45:^010f}|')       # 指定空位補 0 (浮點數補在小數)
|123.450000|
>>> print(f'|{123.45:^010.2f}|')    # 指定空位補 0 (浮點數整數小數均補 0)
|00123.4500|

在對齊格式前指定填充字元的範例如下 : 

>>> print(f'{"Hello World":=<20s}')      # 靠左對齊空位以 = 填充
Hello World=========
>>> print(f'{"Hello World":=^20s}')      # 置中對齊空位以 = 填充
====Hello World=====
>>> print(f'{"Hello World":=>20s}')       # 靠右對齊空位以 = 填充
=========Hello World
>>> print(f'{123:*^20d}')           # 置中對齊空位以 * 填充       
********123*********
>>> print(f'{123:*^020d}')         # 置中對齊空位以 * 填充 (補 0 無效)
********123*********

下面是精確度格式的範例 : 

>>> print(f'圓周率={3.1415926:.1f}')    # 四捨五入到小數 1 位
圓周率=3.1
>>> print(f'圓周率={3.1415926:.3f}')     # 四捨五入到小數 3 位
圓周率=3.142
>>> print(f'{0.123456789:.2e}')               # 四捨五入到小數 2 位
1.23e-01
>>> print(f'{0.123456789:.3e}')               # 四捨五入到小數 3 位
1.235e-01
>>> print(f'{0.123456789:.4e}')               # 四捨五入到小數 4 位
1.2346e-01
>>> print(f'{"Hello":.3s}')                       # 輸出字串中的前 3 字元
Hel
>>> print(f'{"Hello":.7s}')                       # 輸出字串中的前 7 字元 
Hello

注意, 此處因 f 字串使用了單引號, 故 Hello 外面要交替改用雙引號. 

斷斷續續寫了三周終於把格式化測試完畢, 好累. 

參考 : 


沒有留言:

張貼留言