使用者:Xyy23330121/Python/格式化字符串
格式化字符串是一種字符串處理的方法。
str.format
方法可以按模式更改字符串中的內容。我們用以下示例來展示該方法的特徵:
a = "{} World"
print(a) #输出:{} World
print(a.format("Hello")) #输出:Hello World
print(a) #输出:{} World
可以看出,a.format("Hello")
輸出了字符串 a
被替換掉大括號 {}
的版本,沒有更改字符串本身。
我們可以按順序設置以下內容,從而進行更高級的替換。
字符串中,如果不指定任何內容,大括號會被按輸入參數的順序替換。
print("{} {}".format("Hello", "World", "!")) #输出:Hello World
大括號中間如果有索引,則會按輸入參數的索引替換內容。
print("{1} {2}".format("Hello", "World", "!")) #输出:World !
print("{0} {0}".format("Hello", "World", "!")) #输出:Hello Hello
大括號中間如果有標識符,則會按照標識符,查找傳入的參數名稱,來確定替換的內容。
print("{first} {second}".format(first = "Hello", third = "World", second = "!")) #输出:Hello !
print("{third} {third}".format(first = "Hello", third = "World", second = "!")) #输出:World World
在指定了參數後,我們還可以進一步指定參數的元素或屬性。
我們可以給輸入的內容指定索引。
print("{0[0]} {2}".format("Hello", "World", "!")) #输出:H !
要注意,此時索引僅支持非負整數。如果輸入以下的內容,就會報錯:
print("{0[0:]} {2}".format("Hello", "World", "!"))
#TypeError: string indices must be integers, not 'str'
在替換時,Python 如果識別到方括號裡面有不在 0
~9
中的字符,就會把索引作為字符串傳入。也就是說,在本例中,指定的替換內容是"Hello"["0:"]
,而非"Hello"[0:]
。這對於參數是字典的時候很有幫助,但對於參數是字符串、元組或列表的時候則相反。
解決方法見之後的 類 章節。
print("{0.start} {2}".format(range(3), "World", "!")) #输出:0 !
類似索引,我們也可以指定屬性。
使用索引或屬性的次數是沒有限制的。比如:
print("{0[0][1]} {2}".format(["Hello"], "World", "!")) #输出:e !
字符 | 意思 |
---|---|
s |
用str 函數轉換
|
r |
用repr 函數轉換
|
a |
用ascii 函數轉換
|
在確定了用於替換的內容後,我們可以指定轉換方式。
print("{0[0]!s} {2}".format(["Hello"], "World", "!")) #输出:Hello !
通過輸入 !
,再輸入代表轉換方式的字符,我們可以決定如何把參數的內容轉換為字符串。以上面的0[0]!s
為例,此時,Python 會用 str(0[0])
(即 str(["Hello"][0])
)的內容去替換原字符串的內容。
repr
函數會嘗試返回一串字符串,使得程序員按照字符串輸入內容,就能直接生成對應的對象。比如:
print(str("114514")) #输出:114514
print(repr("114514")) #输出:'114514'
如果程序員按照 repr
函數返回的字符串,輸入了 '114514'
。那麼該程序員會得到與 repr
函數參數相同的一個對象。
<generator object <genexpr> at *>
中的*
是程序運行時,該對象被存儲於內存中的位置,或者說,指向該對象的指針。在每次運行中,由於存儲對象所使用的內存位置不同,該值也是不同的。但這也不絕對,比如:
print(str(i for i in range(3))) #输出:<generator object <genexpr> at *>
print(repr(i for i in range(3))) #输出:<generator object <genexpr> at *>
repr
函數返回的結果,並非創建參數對象時使用的 i for i in range(3)
。此時,哪怕使用 repr
函數,對於程序員得到相同的對象也毫無幫助。
ascii
函數會返回 repr
函數返回結果的轉義。它會將 repr
函數返回結果中、任何非 ascii 字符的內容,用轉義序列 \x
、\u
和 \U
來進行替代。
我們還可以用「格式規格迷你語言」設置更多內容。
print("{0!s:-^9}".format(123)) #输出:---123---
通過輸入 :
,再輸入格式規格迷你語言,我們可以進行更多設置。
print("{0!s:=}".format(123))
!s
,則對於之後的設置 :=
而言,傳入的參數就相當於 str(123)
,即'123'
——這是個字符串。從而任意僅對數字類型有效的選項在此時都會出錯。我們可以添加以下的字符,來表示如何進行對齊:
字符 | 解釋 |
---|---|
< |
左對齊 (這是大多數對象的默認值) |
> |
右對齊 (這是對數字的默認值) |
^ |
居中 |
= |
(僅對數字有效)在符號後填充 |
其中,=4
代表數字會被填充為 - 12
的形式——在符號後填充字符,而非右對齊時在符號左側進行填充。
在指定了對齊方式後,我們可以在對齊方式的字符之前添加一個字符,指定以該字符進行填充。比如:$<
代表左對齊,不足的部分用 $
填充。
這些行為類似於之前學過的 字符串的操作:居中與對齊 的內容,與之前學過的內容類似,只有設置了字符串的長度、大於由 str.format
的參數得到的字符串的長度後,這裡的設置才有用。
字符 | 解釋 |
---|---|
+ |
除負數要添加減號外,在正數前也添加一個加號。 |
- |
僅在負數前添加減號。 |
|
(空格)在正數前添加一個空格作為符號。 |
我們可以設置數字前是否添加符號。詳細見右表。
添加字符 z
以應用此選項。
在浮點數進行轉換後,有可能會出現-0
、-0.0
之類的情況。這種情況一般是負的接近零的小數捨入導致的,也可能是轉換了 float("-0")
。
如果添加了字符z
,Python 就會對這種情況進行修改。使其按照之前的符號選項,變為 0.0
、+0.0
或 (空格)0.0
。
添加字符 #
以應用此選項。
對於整數,如果之後設置了以二進制、八進制或十六進制進行輸出。此選項會在輸出值前添加0b
、0o
、0x
或0X
前綴。
對於浮點數和複數,它會使得轉換結果總是包含小數點(即使轉換結果不帶小數部分)。
對於 g
或 G
轉換,末尾的零不會從結果中被移除。
添加字符 0
以應用此選項。
在沒有設置「對齊與填充選項」時。對於數字,如果應用此選項,相當於將之前的「對齊與填充選項」設置為 0=
,即「在符號後,用 0
進行填充」;而對於字符串或其它對象,相當於將填充字符設置為 0
。
如果設置了「對齊與填充選項」,則會優先使用「對齊與填充選項」中的設置。如果「對齊與填充選項」未指定填充字符,則該設置會將填充字符設置為 0
。
可以輸入正整數來決定字符串的長度。如果字符串未達到長度,就會按照之前「對齊與填充選項」的設置,對字符串進行填充。
在分隔符這裡有兩個選項:,
和 _
,
選項僅對浮點數和表示類型為 n
的整數有效,它會將 ,
作為千位分隔符添加到整數或浮點數中。
_
選項對浮點數或表示類型為 n
的整數時,會將 _
作為千位分隔符添加到整數或浮點數中。而在使用二進制、八進制或十六進制輸出的時候,會每四個數字插入一個下劃線。
通過添加 .
再輸入正整數,可以設置精度或字符串的最大長度。它僅對表示類型為 f
、F
或 g
、G
的浮點數,以及對字符串有效。
對於表示類型為 e
、E
或 f
、F
的浮點數,它代表小數點後應顯示的數位。
對於表示類型為 g
或 G
的浮點數,它代表小數點前後總共顯示的數位。
對於字符串,它代表字符串的最大大小。如果超出這個大小,就會截斷之後的部分。
最後,我們可以設置表示類型。
字符串可使用的表示類型如下表:
選項 | 解釋 |
---|---|
s |
(默認)作為字符串輸出 |
(省略) | 使用默認選項 |
整數可使用的表示類型如下表:
選項 | 解釋 |
---|---|
b |
用二進制格式輸出 |
o |
用八進制格式輸出 |
d |
(默認選項)用十進制格式輸出,不支持分隔符。 |
x |
用十六進制格式輸出,輸出時使用小寫字母,比如 1bf52 。
|
X |
用十六進制格式輸出,輸出時使用大寫字母,比如 1BF52 。
|
n |
用十進制格式輸出,支持分隔符。 |
c |
轉換成對應的 ascii 字符進行輸出。 |
(省略) | 使用默認選項 |
浮點數可使用的表示類型如下表:
選項 | 解釋 |
---|---|
e |
用科學計數法輸出,默認精度為6,即小數點後默認保留6位。比如1.000000e0 特別的,和精度無關,nan 會輸出為 |
E |
用科學計數法輸出,但是中間的字符會大寫。nan 和 inf 也會被輸出為大寫。 |
f |
用定點表示法輸出,默認精度為6,即小數點後默認保留6位。比如1.000000 特別的,和精度無關,nan 會輸出為 |
F |
類似 f ,但 nan 和 inf 會被輸出為大寫。
|
g |
用科學計數法表示時,如果指數部分大於等於-4 而小於精度(默認精度為6),則會用定點表示法輸出。反之,用科學計數法輸出。特別的,和精度無關,nan 會輸出為 |
G |
類似 g ,但輸出會大寫。
|
n |
這種方式的輸出,按照 Python 文檔的說明:「類似g ……」。由於 Python 文檔不夠詳細,我們在下面對照示例和輸出研究它的性質。
|
% |
轉換成百分比格式進行輸出。具體來講,是將數字乘 100 ,然後用 f 格式輸出,再在輸出結果後添加一個百分號。
|
(省略) | 這種方式的輸出,按照 Python 文檔的說明:「類似g ……」。由於 Python 文檔不夠詳細,我們在下面對照示例和輸出研究它的性質。
|
以上表示類型還可以用於 decimal 對象。關於 decimal 類型,參見 Python 文檔,這裡不多敘述。關於這些表示類型對 decimal 對象的行為,請讀者查閱 Python 文檔進行補充。
n
的示例及輸出表示類型 n
時,對齊方式和填充、符號選項、z
選項都會按照最平凡的方式產生作用。但分隔符、#
選項等選項的行為值得進行一些測試。我們看以下示例:
#默认设置
#默认是使用小写。
print("{:n}".format(1000.0)) #输出:1000
print("{:n}".format(12.345)) #输出:12.345
print("{:n}".format(float("-inf"))) #输出:-inf
print("{:n}".format(float("nan"))) #输出:nan
#分隔符
#print("{:,n}".format(1000.0)) #输出:ValueError: Cannot specify ',' with 'n'.
#print("{:_n}".format(1000.0)) #输出:ValueError: Cannot specify '_' with 'n'.
#保留符号
#无论如何,保留小数点后2位。
print("{:#n}".format(1000.0)) #输出:1000.00
print("{:#n}".format(1234.5)) #输出:1234.50
#精度
#如果数字 > 10**精度,则四舍五入后输出定点表示法。反之,则四舍五入后输出科学计数法。
print("{:.3n}".format(1000.0)) #输出:1e+03
print("{:.4n}".format(1000.0)) #输出:1000
print("{:.3n}".format(12.345)) #输出:12.3
print("{:.2n}".format(12.345)) #输出:12
print("{:.1n}".format(12.345)) #输出:1e+01
#默认精度
#默认精度为6。
print("{:n}".format(1234567.0)) #输出:1.23457e+06
#保留符号 + 精度
#在保留符号 + 精度时,总是使输出的数字位数等于精度。
print("{:#.2n}".format(1000.0)) #输出:1.0e+03
print("{:#.3n}".format(1000.0)) #输出:1.00e+03
print("{:#.4n}".format(1000.0)) #输出:1000.
print("{:#.5n}".format(1000.0)) #输出:1000.0
print("{:#.3n}".format(float("-0")))#输出:-0.00
省略表示類型時,對齊方式和填充、符號選項、z
選項以及單獨的保留符號選項都會按照最平凡的方式產生作用。但分隔符、#
選項等選項的行為值得進行一些測試。我們看以下示例:
#默认设置
#默认设置使用小写
print("{}".format(1000.0)) #输出:1000.0
print("{}".format(12.345)) #输出:12.345
print("{}".format(float("-inf"))) #输出:-inf
print("{}".format(float("nan"))) #输出:nan
#分隔符
print("{:,}".format(1000.0)) #输出:1,000.0
print("{:_}".format(1000.0)) #输出:1_000.0
#精度
#如果数字 > 10**(精度+1),则四舍五入后输出定点表示法。反之,则四舍五入后输出科学计数法。
print("{:.4}".format(1000.0)) #输出:1e+03
print("{:.5}".format(1000.0)) #输出:1000.0
#默认精度
#默认精度足以精确表示输入的值。
print("{:}".format(1234567.0)) #输出:1234567.0
#保留符号 + 精度
#在保留符号 + 精度时,总是使输出的数字位数等于精度。
print("{:#.2}".format(1000.0)) #输出:1.0e+03
print("{:#.3}".format(1000.0)) #输出:1.00e+03
print("{:#.4}".format(1000.0)) #输出:1.000e+03
print("{:#.5}".format(1000.0)) #输出:1000.0
print("{:#.3}".format(float("-0")))#输出:-0.00
我們將利用這一章節的機會,簡單學習 Python 文檔中,語句語法的表現形式。在本章節所述的 Python 文檔中,我們看到了以下的內容。
replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name ::= arg_name ("." attribute_name | "[" element_index "]")*
arg_name ::= [identifier | digit+]
attribute_name ::= identifier
element_index ::= digit+ | index_string
index_string ::= <any source character except "]"> +
conversion ::= "r" | "s" | "a"
format_spec ::= format-spec:format_spec
我們從第一行看起,第一行的內容為:
- 結構 replacement_field 由以下幾個部分組成:
- 前綴
{
- 可選:結構 field_name
- 可選:
- 前綴
!
- 結構 conversion
- 前綴
- 可選:
- 前綴
:
- 結構 format_spec
- 前綴
- 後綴
}
- 前綴
而第二行的內容為:
- 結構 field_name 由以下幾個部分組成:
- 結構 arg_name
- 任意個數的:
- 二選一(其一):
- 前綴
.
- 結構 attribute_name
- 前綴
- 二選一(其二):
- 前綴
[
- 結構 element_index
- 後綴
]
- 前綴
- 二選一(其一):
這種表示方法和正則表達式很相似。|
表示或、[]
表示之間的內容可選、""
表示之間的內容只是對應字符、而 ()*
表示中間的內容可以重複 0 至任意次。在倒數第三行,文檔在 <>
中間添加了一個注釋。
如果能直接讀懂這些內容,讀者就可以不依賴於文檔中的語言描述,直接解析語句的語法。這對於文檔中、語言描述不夠明確的情況時很好用。
根據上面的文檔,讀者還可以自行設置一套格式化語法和方式。具體讀懂上面的文檔,可能需要讀者學習之後的類章節之後才能做到。
除上面的文檔外,還可以用 類的__format__方法 來自定義格式化語法。
f 字符串是一種創建字符串的方法。類似「原始字符串」在創建時就不進行轉義、「f字符串」在創建時就立即被格式化。
value = "Python"
fstr1 = f"{value}"; print(fstr1) #输出:Python
fstr2 = f"{value * 2}"; print(fstr2) #输出:PythonPython
f 字符串會把 {}
之間的內容,當成普通的 Python 表達式來求值,把表達式返回的結果轉換為字符串並輸出到原字符串內。
在使用表達式時,有以下注意事項:
- 空表達式不被允許。
比如f"{}"
等,是不被允許的。 - 可以使用注釋。
- 表達式中不能出現作為運算符的
=
。
=
符號只要不作為賦值表達式而出現,也是可以在表達式中的。比如:
fstr3 = f"{ '= '* 3 }"
print(fstr3) #输出:===
可以用以下方式使用注釋:
fstr = f"{1 + 2 #输出:3}"
}"
print(fstr) #输出:3
在注釋部分結束後,應當在下一行補一個 }"
(或 }'''
等,取決於創建 f 字符串時使用的引號)。
在表達式末尾,可以添加 =
。此時,會在 f 字符串中同時輸出表達式的字符與表達式的結果。比如:
value = "Python"
fstr1 = f"{value = }"
print(fstr1)
fstr2 = f"{value * 2=}"
print(fstr2)
輸出為:
value = 'Python'
value * 2='PythonPython'
等號前後以及表達式中的空格都會被原樣輸出。
在= 標記的後面,可以設置把「表達式返回值」轉換為字符串的方式。具體有三種轉換方式:
!s
(默認)用str()
轉換。!r
(默認)用repr()
轉換。!a
(默認)用ascii()
轉換。
與 str.format 類似,這裡也可以使用格式規格迷你語言。在 str.format 中使用格式規格迷你語言的方法可以完全照搬到這裡。
但在 str.format 之外,這裡使用的格式規格迷你語言可以「按替換規則設置」。比如:
width = 6
precision = 4
value = 114.514
fstr = f"{value:@>{width}.{precision}}"
print(fstr) 输出:@114.5
在解析時,Python 先按規則替換 {width}
和 {precision}
的內容,再替換 {value:@>6.4}
的內容。
特別的,{{
會被替換為 {
,而 }}
會被替換為 }
。比如:
fstr = f"}} {{}} {1+2:$^{1+2}}"
print(fstr)
輸出為:
} {} $3$
如同上述示例,最後的 }}
分別與前面兩個單獨的 {
配對。如果有配對,就不會按轉義規則進行替換。
這種方法很像是 C 語言中 printf 函數格式化字符串的方式。這種方法可處理的類型範圍較窄,並且更難以正確使用,但更為快速。
字符串和元組 / 字典之間支持一種特殊的二元運算:格式化運算,其運算符是%
。
示例:
s = "%(a)s %(b)s %(c)s"
d = {"a":"Py", "b":"th", "c":"on"}
print(s % d) #输出:Py th on
s = "%s %s %s"
t = ("Py", "th","on")
print(s % t) #输出:Py th on
字符串中,被替換的部分由以下幾個部分組成:
部分 | 示例 | 解釋 |
---|---|---|
% | % |
字符% 。
|
鍵 (可選) |
(key_name) |
用括號括起的、字典鍵的名稱。 |
轉換旗標 (可選) |
此處列舉的旗標可以組合。 | |
# |
轉換數字時,使用「替代形式」(見「轉換類型」) | |
0 |
轉換數字時,用0填充 | |
- |
轉換值靠左對齊。如果同時給出旗標0 ,則覆蓋後者。比如旗標 -0 等同於旗標- ,而旗標0- 等同於旗標0 。
| |
|
(空格旗標)正數或空字符串前會留一個空格 | |
+ |
轉換數字時,前面一定有符號。 如果和空格旗標一起使用,此旗標產生的符號字符會覆蓋空格旗標的效果。 | |
最小寬度 (可選) |
* |
由元組中、下一個元素的數值決定。 如果使用字典與字符串作格式化運算,則不能使用此項。 |
42 |
任意非負整數 | |
精度 (可選) |
.42 |
由. 開頭的、任意非負整數
|
.* |
由元組中、下一個元素的數值決定。 如果使用字典與字符串作格式化運算,則不能使用此項。 | |
長度修飾符 (可選) |
h |
長度修飾符可以為h 、l 或L 設置此項僅為了和 printf 函數一致,沒有任何作用。 |
轉換類型 (必須) |
s |
這裡給出的內容決定了內容轉換為字符串的方式。 |
轉換符 | 含意 | 替代形式 |
---|---|---|
d |
有符號十進制整數。 | |
i |
有符號十進制整數。 | |
o |
有符號八進制數。 | 以0o 開頭
|
u |
過時類型 -- 等價於 d 。 |
|
x |
有符號十六進制數(小寫)。 | 以0x 開頭
|
X |
有符號十六進制數(大寫)。 | 以0X 開頭
|
e |
浮點指數格式(小寫)。 | (無論小數點後有沒有數值) 總是包含小數點。 |
E |
浮點指數格式(大寫)。 | |
f |
浮點十進制格式。 小數點後的數碼位數由精度決定,默認為 6。 | |
F |
浮點十進制格式。 小數點後的數碼位數由精度決定,默認為 6。 | |
g |
浮點格式。 如果指數小於 -4 或不小於精度,則等同於 e ,否則,等同於 f 。
|
末尾的零不會被移除。 (無論小數點後有沒有數值) 總是包含小數點。 |
G |
浮點格式。 如果指數小於 -4 或不小於精度,則等同於 E ,否則,等同於 F 。
| |
c |
單個字符(接受整數或單個字符的字符串)。 | |
r |
repr() 如果指定精度,則輸出會被截短至精度 |
|
s |
str() 如果指定精度,則輸出會被截短至精度 |
|
a |
ascii() 如果指定精度,則輸出會被截短至精度 |
|
% |
不轉換參數,在結果中輸出一個 % 字符。 |