1. 程式人生 > >Python 中 str.format() 方法詳解

Python 中 str.format() 方法詳解

Python 中 str.format() 方法詳解

轉載請註明出處:https://blog.csdn.net/jpch89/article/details/84099277


文章目錄


0. 參考資料


1. 術語說明

  • str.format() 方法通過字串中的花括號 {} 來識別替換欄位 replacement field,從而完成字串的格式化。
  • 替換欄位 由欄位名 field name 和轉換欄位 conversion field 以及格式說明符 format specifier
    組成,即一般形式為 {欄位名!轉換欄位:格式說明符}
  • 欄位名分為簡單欄位名 simple field name 和複合字段名 compound field name
  • 轉換欄位格式說明符都是可選的。

2. 簡單欄位名

2.1 簡單欄位名的說明

簡單欄位名有三種寫法:

  • 省略不寫 {}
  • 數字 {十進位制非負整數}
  • 變數名 {合法的Python識別符號}

2.2 省略欄位名

花括號內省略欄位名,傳遞位置引數

  • 替換欄位形式: {}
  • 注意:花括號個數可以少於位置引數的個數,反之不然。
# 省略欄位名傳遞位置引數
print('我叫{},今年{}歲。'.format('小明', 18))
"""
我叫小明,今年18歲。
"""

# 花括號個數可以少於位置引數的個數
print('我愛吃{}和{}。'.format('香蕉', '蘋果', '大鴨梨'))
"""
我愛吃香蕉和蘋果。
"""

# 花括號個數多於位置引數的個數則會報錯
# print('我還吃{}和{}。'.format('西紅柿'))
"""
IndexError: tuple index out of range
"""

2.3 數字形式的簡單欄位名

可以通過數字形式的簡單欄位名傳遞位置引數

  • 數字必須是大於等於 0 的整數。
  • 帶數字的替換欄位可以重複使用
  • 數字形式的簡單欄位名相當於把 format 中的所有位置引數整體當作一個元組,通過欄位名中的數字進行取值。
  • {0} 等價於 tuple[0],所以花括號內的數字不能越界
# 通過數字形式的簡單欄位名傳遞位置引數
print('身高{0},家住{1}。'.format(1.8, '銅鑼灣'))
"""
身高1.8,家住銅鑼灣
"""

# 數字形式的簡單欄位名可以重複使用。
print('我愛{0}。\n她今年{1}。\n{0}也愛我。'.format('阿香', 17))
"""
我愛阿香。
她今年17。
阿香也愛我。
"""

# 體會把所有位置引數整體當成元組來取值
print('阿香愛吃{1}、{3}和{0}。'.format(
    '榴蓮', '臭豆腐', '皮蛋', '鯡魚罐頭', '螺獅粉'))
"""
阿香愛吃臭豆腐、鯡魚罐頭和榴蓮。
"""

# 嘗試一下越界錯誤
# print('{1}'.format('錯誤用法'))
"""
IndexError: tuple index out of range
"""

2.4 變數名形式的簡單欄位名

使用變數名形式的簡單欄位名傳遞關鍵字引數

  • 關鍵字引數的位置可以隨意調換。
# 使用變數名形式的簡單欄位名傳遞關鍵字引數
print('我大哥是{name},今年{age}歲。'.format(name='阿飛', age=20))
"""
我大哥是阿飛,今年20歲。
"""

# 關鍵字引數的順序可以隨意調換
print('我大哥是{name},今年{age}歲。'.format(age=20, name='阿飛'))
"""
我大哥是阿飛,今年20歲。
"""

2.5 簡單欄位名的混合使用

  • 混合使用數字形式和變數名形式的欄位名,可以同時傳遞位置引數和關鍵字引數。
  • 關鍵字引數必須位於位置引數之後。
  • 混合使用時可以省略數字。
  • 省略欄位名 {} 不能和數字形式的欄位名 {非負整數} 同時使用。
# 混合使用數字形式和變數名形式的欄位名
# 可以同時傳遞位置引數和關鍵字引數
print('這是一個關於{0}、{1}和{girl}的故事。'.format(
    '小明', '阿飛', girl='阿香'))
"""
這是一個關於小明、阿飛和阿香的故事。
"""

# 但是關鍵字引數必須位於位置引數之後
# print('這是一個關於{0}、{1}和{girl}的故事。'.format(
    # '小明', girl='阿香' , '阿飛'))
"""
SyntaxError: positional argument follows keyword argument
"""

# 數字也可以省略
print('這是一個關於{}、{}和{girl}的故事。'.format(
    '小明', '阿飛', girl='阿香'))

# 但是省略欄位名不能和數字形式的欄位名同時出現
# print('這是一個關於{}、{1}和{girl}的故事。'.format(
#     '小明', '阿飛', girl='阿香'))
"""
ValueError: cannot switch from automatic field numbering to manual field specification
"""

2.6 使用元組和字典傳參

str.format() 方法還可以使用 *元組**字典 的形式傳參,兩者可以混合使用。
位置引數、關鍵字引數、*元組**字典 也可以同時使用,但是要注意,位置引數要在關鍵字引數前面,*元組 要在 **字典 前面。

# 使用元組傳參
infos = '鋼鐵俠', 66, '小辣椒'
print('我是{},身價{}億。'.format(*infos))
"""
我是鋼鐵俠,身家66億。
"""
print('我是{2},身價{1}億。'.format(*infos))
"""
我是小辣椒,身家66億。
"""

# 使用字典傳參
venom = {'name': '毒液', 'weakness': '火'}
print('我是{name},我怕{weakness}。'.format(**venom))
"""
我是毒液,我怕火。
"""

# 同時使用元組和字典傳參
hulk = '綠巨人', '拳頭'
captain = {'name': '美國隊長', 'weapon': '盾'}
print('我是{}, 我怕{weapon}。'.format(*hulk, **captain))
print('我是{name}, 我怕{1}。'.format(*hulk, **captain))

"""
我是綠巨人, 我怕盾。
我是美國隊長, 我怕拳頭。
"""

# 同時使用位置引數、元組、關鍵字引數、字典傳參
# 注意:
# 位置引數要在關鍵字引數前面
# *元組要在**字典前面
tup = '鷹眼',
dic = {'weapon': '箭'}
text = '我是{1},我怕{weakness}。我是{0},我用{weapon}。'
text = text.format(
    *tup, '黑寡婦', weakness='男人', **dic)
print(text)
"""
我是黑寡婦,我怕男人。我是鷹眼,我用箭。
"""

3. 複合字段名

3.1 複合字段名的說明

  • 同時使用了數字和變數名兩種形式的欄位名就是複合字段名
  • 複合字段名支援兩種操作符:
    • [] 方括號
    • . 點號

3.2 . 點號的使用

傳遞位置引數

  • 替換欄位形式:{數字.屬性名}
  • 只有一個替換欄位的時候可以省略數字
# 複合字段名中使用點號傳遞物件屬性
class Person:
    def __init__(self, name, addr):
        self.name = name
        self.addr = addr


p = Person('辣妹子', '重慶')

# 點號用法:傳遞位置引數
print('我是{0.name},家在{0.addr}。'.format(p))
"""
我是辣妹子,家在重慶。
"""

# 當只有一個替換欄位的時候可以省略數字
print('{.name}辣!'.format(p))
"""
辣妹子辣!
"""

# 試試傳遞檔案物件的屬性
f = open('out.txt', 'w')
print('檔名為:{.name}'.format(f))
f.close()
"""
檔名為:out.txt
"""

傳遞關鍵字引數

  • 替換欄位形式:{關鍵字引數名.屬性名}
# 點號用法:傳遞關鍵字引數
print('我是{girl.name},家在{girl.addr}。'.format(girl=p))
# 和上一句等價
print('我是{p.name},家在{p.addr}。'.format(p=p))
"""
我是辣妹子,家在重慶。
我是辣妹子,家在重慶。
"""

3.3 [] 方括號的使用

傳遞位置引數

  • 用列表傳遞位置引數
  • 用元組傳遞位置引數
  • 用字典傳遞位置引數
# 方括號用法:用列表傳遞位置引數
infos = ['阿星', 9527]
food = ['霸王花', '爆米花']
print('我叫{0[0]},警號{0[1]},愛吃{1[0]}。'.format(
    infos, food))
"""
我叫阿星,警號9527,愛吃霸王花。
"""

# 方括號用法:用元組傳遞位置引數
food = ('殭屍', '腦子')
print('我叫{0[0]},年齡{1},愛吃{0[1]}。'.format(
    food, 66))
"""
我叫殭屍,年齡66,愛吃腦子。
"""

# 方括號用法:用字典傳遞位置引數
dic = dict(name='阿星', pid=9527)
print('我是{[name]}!'.format(
    dic))
# 多個替換欄位,不能省略數字
print('我是{0[name]},警號{0[pid]}。'.format(
    dic))
"""
我是阿星!
我是阿星,警號9527。
"""

傳遞關鍵字引數

  • 用列表傳遞關鍵字引數
  • 用元組傳遞關鍵字引數
  • 用字典傳遞關鍵字引數
# 方括號用法:傳遞關鍵字引數
names = ['皮卡丘']
dic = {'name': '妙蛙花'}
skills = ('十萬伏特', '飛葉快刀')
text = '我是{names[0]},我會{skills[0]}。我是{dic[name]},我會{skills[1]}。'
text = text.format(names=names, skills=skills, dic=dic)
print(text)
"""
我是皮卡丘,我會十萬伏特。我是妙蛙花,我會飛葉快刀。
"""

4. 轉換欄位

轉換欄位 conversion field 的取值有三種,前面要加 !

  • s:傳遞引數之前先對引數呼叫 str()
  • r:傳遞引數之前先對引數呼叫 repr()
  • a:傳遞引數之前先對引數呼叫 ascii()

ascii() 函式類似 repr() 函式,返回一個可以表示物件的字串。
但是對於非 ASCII 字元,使用 \x\u 或者 \U 轉義。

# 轉換欄位
print('I am {!s}!'.format('Bruce Lee 李小龍'))
print('I am {!r}!'.format('Bruce Lee 李小龍'))
print('I am {!a}!'.format('Bruce Lee 李小龍'))
"""
I am Bruce Lee 李小龍!
I am 'Bruce Lee 李小龍'!
I am 'Bruce Lee \u674e\u5c0f\u9f99'!
"""

5. 格式說明符

  • 替換欄位中,格式說明符前面有一個冒號 :
    {欄位名!轉換欄位:格式說明符}
  • 其中格式說明符本身可以是一個欄位名,比如:
print('{0:{1}}'.format(3.14159, '.4f'))
"""
3.1416
"""

5.1 標準格式說明符的格式

  • 如果不通過重寫 __format__ 方法來進行自定義的話,標準格式說明符的形式如下。其中方括號是可選的。
    [[fill]align][sign][#][0][width][grouping_option][.precision][type]
  • 中文形式可以寫作:
    [[填充]對齊方式][正負號][#][0][寬度][分組選項][.精度][型別碼]

5.2 填充與對齊方式

填充

  • 只能是一個字元
  • 不指定預設用空格填充
  • 如果指定填充字元,則必須要同時指定對齊方式

對齊方式的取值:

  • <:左對齊
  • >:右對齊
  • ^:居中
  • =:在正負號(如果有的話)和數字之間填充,該對齊選項僅對數字型別有效。
    它可以輸出類似 +0000120 這樣的字串。

注意:

  • 如果不給定最小寬度 width,對齊方式毫無意義。

5.3 正負號

  • 正負號選項僅對數字型別生效
  • 取值有三種:
    • + 正數前面新增正號,負數前面新增負號
    • - 僅在負數前面新增負號(預設行為)
    • 空格:正數前面需要新增一個空格,以便與負數對齊
# 正負號
print('{:哈=+8.2f}'.format(3.14159))
print('{:哈=+8.2f}'.format(-3.14159))
print('{:哈=+8.2f}'.format(0))
print('{:哈=+8.2f}'.format(-0))
"""
+哈哈哈3.14
-哈哈哈3.14
+哈哈哈0.00
+哈哈哈0.00
"""

5.4 # 號

# 號:

  • 給u二進位制數加上 0b 字首
  • 給八進位制數加上 0o 字首
  • 給十六進位制數加上 0x 字首

5.5 最小寬度

最小寬度 width

  • 如果不指定,最小欄位寬度由內容決定,與內容相等
  • 如果最小寬度前面有一個前導 0,意味著用 0 填充
    這等價於指定了 0= 的填充和對齊方式

5.6 分組選項

分組選項 grouping_option 的取值有兩種:

  • 逗號 ,:使用逗號對數字以千為單位進行分隔。n 型別的數字可以使用本地化的分隔符。

n 型別在本機無法使用分組選項 ,
原因可能是中文沒有數字分隔符

# n 型別使用本地化的分組選項 ,
# 此項報錯,我懷疑是因為中文沒有數字的分隔符
# print('數字:{0:,n}'.format(6666))
"""
ValueError: Cannot specify ',' with 'n'.
"""

# 使用 d 型別確實是可以的
print('數字:{0:,d}'.format(6666))
"""
數字:6,666
"""
  • 下劃線 _:使用下劃線對浮點數和 d 型別的整數以千為單位進行分隔。對於 boxX 型別,每四位插入一個下劃線,其他型別都會報錯。
# 分組選項 _ 作用於 b 型別
print('數字:{0:_b}'.format(0b100111011))
"""
數字:1_0011_1011
"""

# 分組選項 _ 作用於 o 型別
print('數字:{0:_o}'.format(0o426754316))
"""
數字:4_2675_4316
"""

# 分組選項 _ 作用於 x 型別
print('數字:{0:_x}'.format(0x2a846e98d))
"""
數字:2_a846_e98d
"""

# 分組選項 _ 作用於 X 型別
print('數字:{0:_X}'.format(0X2a846e98d))
"""
數字:2_A846_E98D
"""

# 分組選項 _ 作用於其他型別(比如 n 型別)
# print('字串:{0:_n}'.format(1234567))
"""
ValueError: Cannot specify ',' with 'n'.
"""

5.7 精度

精度:

  • 精度指定了小數點後面要展示多少位小數
  • 對於非數字型別,精度指定了最大欄位寬度
  • 整數型別不能指定精度
# 對於非數字型別,精度指定最大欄位寬度
print('{0:.3}'.format('哇哈哈哈哈哈'))
"""
哇哈哈
"""
# 整數型別不能指定精度
print('{:.3d}'.format(666))
"""
ValueError: Precision not allowed in integer format specifier
"""

5.8 型別碼

型別碼可以分為三大類:

  • 字串型別
  • 整數型別
  • 浮點數型別

5.8.1 字串型別

  • s 字串型別。這是字串的預設型別,可以省略。
  • None 不指定型別。同 s 型別。
# s 型別
print('{0:s}'.format('略略略'))
# s 型別可以省略
print('{0:}'.format('略略略'))
"""
略略略
略略略
"""

5.8.2 整數型別

  • b 二進位制。
# b 型別:二進位制
print('{0:b}'.format(3))
"""
11
"""
  • c 字元。把整數轉換為相應的 Unicode 字元,然後再列印。
# c 型別:把整數轉換成 unicode 字元
print('{:c}'.format(97))
"""
a
"""
  • d 十進位制整數。
# d 型別:十進位制整數
print('{:d}'.format(666))
"""
666
"""
  • o 八進位制數。
# o 型別:八進位制數
print('{:o}'.format(10))
"""
12
  • x 十六進位制數,af 小寫。
# x 型別:十六進位制數,a到f小寫
print('{:x}'.format(15))
"""
f
"""
  • X 十六進位制數,AF 大寫。
# X 型別:十六進位制數,A到F大寫
print('{:X}'.format(15))
"""
F
"""
  • n 數字 number 型別,與 d 相同,只不過它會使用本地化的數字分隔符。

經試驗,在本機為 n 型別指定任何分組選項(,_)都會報錯。
ValueError: Cannot specify ',' with 'n'.

# n 型別:與d相同,會插入本地化的分隔符
print('{:n}'.format(66666))
# 經試驗,本機無法為 n 指定任何分組選項(,_)
# print('{:,n}'.format(66666))
"""
ValueError: Cannot specify ',' with 'n'.
"""
# print('{:_n}'.format(66666))
"""
ValueError: Cannot specify ',' with 'n'.
"""
  • None 不指定型別,與 d 相同。

5.8.3 浮點數型別

  • e 科學記數法,用 e 來表示指數。預設精度為 6
# e 型別:科學記數法
# 預設精度為 6 位
print('{:e}'.format(1234567.1234567))
"""
1.234567e+06
"""
  • Ee 相同,但是使用大寫的 E 表示指數。
# E 型別:與 e 相同,用大寫 E 表示指數
# 預設精度為 6 位
print('{:E}'.format(1234567.1234567))
# 修改精度為 10 位
print('{:.10E}'.format(1234567.1234567))
"""
1.234567E+06
1.2345671235E+06
"""
  • f 定點記法,預設精度為 6
# f 型別
# 預設精度為 6 位
print('{:f}'.format(1234567.1234567))
"""
1234567.123457
"""
  • F 定點記法,同 f,但是會把 nan 轉換成 NAN,把 inf 轉換成 INF
# F 型別
nan = float('nan')
inf = float('inf')
print('{:F}\n{:F}'.format(nan, inf))
"""
NAN
INF
"""
  • g 通用 general 格式。自動轉換到 e 或者 f 格式,具體的轉換規則在此省略。正無窮、負無窮、正零、負零和非數字分別顯示為 inf-inf0-0nan。指定精度為 0 時等價於精度為 1。預設精度為 6 位。
# g 型別
print('{:g}'.format(1234567.1234567))
print('{:g}'.format(1234.1234))
"""
1.23457e+06
1234.12
"""
  • G 通用 general 格式。自動轉換到 E 或者 F 格式,轉換規則同上,相應表示方式換成大寫。
# g 型別
print('{:g}'.format(1234567.1234567))
print('{:g}'.format(1234.1234))
"""
1.23457e+06
1234.12
"""
  • n 數字 number 型別。跟 g 一樣,只不過用本地化的分隔符來分隔數字。
# n 型別
print('{:n}'.format(1234567.1234567))
print('{:n}'.format(1234.1234))
"""
1.23457E+06
1234.12
"""

# 經試驗,本機指定分組選項會報錯
# print('{:,n}'.format(1234.1234))
"""
ValueError: Cannot specify ',' with 'n'.
"""
# print('{:_n}'.format(1234.1234))
"""
ValueError: Cannot specify ',' with 'n'.
"""
  • % 百分號型別。會將數字乘以 100,然後以 f 定點 fixed-point 格式顯示,最後加上一個百分號 %
# % 型別
print('{:%}'.format(1))
"""
100.000000%
"""
  • None 不指定型別。輸出效果類似呼叫 str() 函式。

6. 補充說明

  • 輸出花括號需要用花括號本身來轉義
# 列印花括號需要使用花括號轉義
print('{{{}}}'.format('張無忌'))
"""
{張無忌}
"""
  • 物件可以自定義格式說明符來替換標準格式說明符,比如 datetime 類。
from datetime import datetime
print("Today is: {0:%a %b %d %H:%M:%S %Y}".format(datetime.now()))
"""
今天是:Thu Nov 15 13:05:09 2018
"""

完成於 2018.11.15