一篇文章我們介紹了4種字符串格式化方法,其中最現代、最直觀的方式是f-string,從Python 3.6開始引入,而且時不時就增加一些超級優雅的小改進。今天,鋼鐵老豆想要繼續給大家展開介紹不同數據類型的格式化選項,以f-string為例,同樣適用于其他格式化方法。
f-string,或稱為格式化字符串字面值,是一種在字符串前加上 `f` 或 `F` 前綴的新語法。通過這種方式,您可以直接在字符串中嵌入表達式,并在運行時計算這些表達式的值。它不僅提高了代碼的可讀性,還加快了字符串處理的速度。
使用 f-string 非常簡單。只需在字符串前加上字母 `f`,并將表達式放在大括號 `{}` 中。
name="張三"
age=30
print(f"你好,{name},你明年就{age + 1}歲了。") # 你好,張三,你明年就31歲了。
除了基本的變量外,你還可以在花括號里調用函數、訪問字典、執行算術運算等。
data={'name': '趙六', 'job': '工程師'}
print(f"{data['name']} 是一名 {data['job']}")
下面,讓鋼鐵老豆更詳細地介紹 Python f-string 的各種格式化選項,滿足不同數據類型的需求。
number=3.14159
print(f"{number:.3f}") # 輸出 3.142
number=3.14159
print(f"{number:10.3f}") # 寬度為10,小數點后3位
number=1234567.89
print(f"{number:,}") # 輸出 1,234,567.89
number=255
print(f"{number:x}") # 輸出 ff
number=255
print(f"{number:o}") # 輸出 377
number=255
print(f"{number:b}") # 輸出 11111111
fraction=0.123
print(f"{fraction:.1%}") # 輸出 12.3%
name="Alice"
print(f"{name:>10}") # 右對齊,寬度為10
name="Alice"
print(f"{name:*^10}") # 使用*填充,居中對齊
text="Hello World"
print(f"{text:.5}") # 輸出 Hello
如果對象實現了 `__format__` 方法,f-string 也可以使用指定的格式代碼來格式化該對象。每當格式化一個對象時(例如,使用`format()`函數或在f-string中引用),Python會查找該對象的`__format__`方法。該方法接收一個格式說明符作為參數,這個說明符可以是空字符串,或是任何有效的格式代碼,您可以在方法內部解釋并應用這些代碼。
例如,如果您正在設計一個財務相關的類,可能會想允許用戶根據不同的貨幣或會計需求選擇不同的顯示格式:
class Money:
def __init__(self, amount):
self.amount=amount
def __format__(self, format_spec):
if format_spec=='usd':
return f"${self.amount:.2f}"
elif format_spec=='eur':
return f"{self.amount:.2f}"
elif format_spec=='clean':
return f"{self.amount:.2f}"
else:
# 默認為美元格式
return f"${self.amount:.2f}"
# 使用自定義格式
money=Money(1234.5)
print(f"{money}") # $1234.50
print(f"{money:'eur'}") # 1234.50
print(f"{money:'clean'}") # 1234.50
這除了增強類的自描述性和靈活性,還可以使對象的字符串表示形式更加友好和符合場景需求。這在創建API、框架或任何需要用戶與您的對象進行交互的應用程序時特別有用。
好了,以上就是不同數據類型常見的格式化選項,f-string 不僅使用簡單,而且非常強大和靈活。
歡迎點贊+收藏+評論+關注,每天學習一點Python小知識,無論基礎、模塊、數據分析、深度學習和Ai,總有你感興趣的。我是鋼鐵老豆,一個30歲轉行IT、自學成為算法工程師、想用Ai點亮孩子小小世界的Pythoner。
經常需要對 Python 浮點數進行格式化和四舍五入,以便在字符串中整齊地顯示計算結果。在 Python 的早期版本中,這樣做很麻煩,因為您需要先對數字進行四舍五入,然后使用字符串連接或舊的字符串格式化技術來完成這項工作。
自從Python 3.6版本開始,文字串插值(更常被稱為格式化文字串或f字符串)允許你以一種更易讀的方式自定義字符串的內容。
一個f字符串是以小寫或大寫字母f為前綴的文字串,并包含在一對花括號{...}中的零個或多個替換字段。每個字段包含一個產生值的表達式。你可以計算字段的內容,但也可以使用函數調用甚至變量。
雖然大多數字符串都有一個恒定的值,但f字符串是在運行時評估的。這使得你可以將不同的數據傳遞到同一個f字符串的替換字段中,并產生不同的輸出。f字符串的這種可擴展性使它們成為一種將動態內容整潔地嵌入字符串中的好方法。然而,盡管f字符串在很大程度上取代了以前的方法,但它們確實有它們的缺點。
例如,一個最常見的對關系數據庫執行的攻擊是SQL注入攻擊。通常,用戶提供參數給SQL查詢,如果查詢是在f字符串內形成的,可能通過傳入惡意命令來損壞數據庫。f字符串也可以在攻擊Python的日志模塊代碼時用于拒絕服務攻擊。
在舊版本的Python中,f字符串有許多其他限制,直到Python 3.12版本才得到解決。本教程中使用的是這個版本。
看一下下面的例子。它向你展示了如何在f字符串中嵌入計算結果:
>>> f"One third, expressed as a float is: {1 / 3}"
'One third, expressed as a float is: 0.3333333333333333'
在沒有任何顯式舍入的情況下,一旦表達式產生了其值,它將以默認的小數位數插入到字符串中。在這里,結果顯示到十六位小數,這在大多數情況下比你所需的精度更高。因此,你可能希望將最終答案舍入到更實用的數字位數。
在本教程中,你將學習如何使用Python的f字符串來格式化浮點數,以滿足你的要求。
為了在Python的f字符串中整潔地顯示格式化浮點數,你可以使用格式說明符。在其最基本的形式中,這允許你定義浮點數顯示的精度,或小數位數。
下面的代碼顯示了與之前相同的計算,只是顯示得更整潔:
>>> f"One third, rounded to two decimal places is: {1 / 3:.2f}"
'One third, rounded to two decimal places is: 0.33'
要在替換字段中使用Python的格式說明符,你需要用冒號(:)將它們與表達式分隔開來。正如你所看到的,你的浮點數已經舍入到兩位小數。你通過在替換字段中添加格式說明符.2f來實現這一點。其中,2是精度,而小寫的f是表示類型的一個示例。稍后你會看到更多這樣的內容。
注意:使用格式指定符時,實際上并不會改變底層數字。您只是改進了它的顯示效果。
Python的f字符串還有自己的小語言,允許你以多種不同的方式格式化輸出。盡管本教程將重點介紹舍入,但這絕對不是你唯一可以使用它們的地方。正如你稍后將看到的,它們的小語言也用于其他字符串格式化技術中。
除了顯示計算結果外,格式說明符的精度部分還可以直接應用于變量和函數調用的返回值:
>>> def total_price(cost):
... return cost * 1.2
...
>>> cost_price=1000
>>> tax=0.2
>>> f"£{1000:,.2f} + £{cost_price * tax:,.2f}=£{total_price(cost_price):,.2f}"
'£1,000.00 + £200.00=£1,200.00'
這次,你在同一個字符串中使用了多個替換字段。第一個字段格式化了一個文字數字,第二個格式化了一個計算結果,而第三個格式化了一個函數調用的返回值。此外,在格式說明符中在小數點(.)之前插入逗號(,),可以在最終輸出中添加千位分隔符。
在日常使用中,你會以固定的小數位數顯示數字,但在進行科學或工程計算時,你可能更喜歡使用有效數字來格式化它們。你的結果則被假定為精確到你所顯示的有效數字的位數。
如果你想將數字四舍五入到有效數字,你可以在格式說明符中使用小寫字母g。你也可以使用大寫字母G,但這會自動將格式切換為科學計數法,適用于大數字。
假設你有一個半徑為10.203米的圓。為了計算其面積,你可以使用這段代碼:
>>> import math
>>> f"Area={math.pi * 10.203**2}"
'Area=327.0435934242156'
你決定使用Python的math模塊提供的π常數值。盡管你的答案看起來非常精確,但其中大部分是無意義的。任何計算的精確度都取決于其組成部分中有效數字最少的數字。在這種情況下,半徑值10.203只包含五個有效數字,比math.pi小,所以最終結果應該舍入到這個值。
更好的編碼方式是:
>>> f"Area={math.pi * 10.203**2:,.5g}"
'Area=327.04'
面積為327.04平方米,精確到五個有效數字。您也可以使用格式說明符將數字顯示為百分比。要手動執行此操作,您需要將數字乘以一百,然后在所需的小數位數前附加一個百分號(%)。您可以通過在小寫f或g的位置使用%表示類型來自動執行所有這些操作。
>>> f"{0.1256:.1%}"
'12.6%'
>>> f"{0.5:.2%}"
'50.00%'
>>> f"{3:.2%}"
'300.00%'
正如您所看到的,.2%已經自動為您處理了乘法、四舍五入和百分比附加。
現在您知道如何處理Python中在f字符串中格式化浮點數的最常見情況。您將在下一節中學到更多內容,但在繼續之前,請展開下面的部分,看看您是否能完成任務。通過解決這些問題,您可以很好地復習和鞏固您到目前為止的理解。
任務1:使用number=64723.4161,看看你是否可以寫一行代碼產生所示的輸出。除了格式說明符需要的數字之外,您的字符串不應包含任何其他數字:
number=64723.4161
# 在這里編寫您的解決方案
'The number 64,723.4161, when rounded to two decimal places, is 64,723.42.'
任務2:從變量numerator=3和denominator=8開始,看看你是否可以寫一行代碼產生所示的輸出。同樣,除了格式說明符所需的數字外,您的字符串不應包含任何其他數字:
numerator=3
denominator=8
# 在這里編寫您的解決方案
'3/8 as a percentage is 37.5%.'
任務3:計算半徑為2.340米的球體的體積。您的答案應顯示為適當數量的有效數字。
現在,是時候繼續學習更多增強字符串中數字顯示的方法了。
固定長度記錄對于保存到文件中非常有用。固定長度文件是指其所有記錄字段都占據相同數量的字符的文件。通常情況下,字段會使用額外的字符進行填充,文本通常使用尾隨空格,數字則使用前導零。
固定長度文件已經存在多年了,今天仍然可以看到它們。盡管像XML和YAML這樣的格式更容易手動閱讀,但固定長度文件仍然具有一些優勢。您的代碼可以非常高效地讀取固定長度記錄,因為每個記錄內的每個字段都位于相同的位置。相比之下,XML解析器通常需要更多的資源,特別是如果您需要處理大量的數據時。
然而,固定長度文件通常比其他格式更具體于應用程序,這意味著您不能輕松地在系統之間傳輸它們。另外,使用XML和YAML解析器可以快速添加和讀取額外的字段。相比之下,更新固定長度字段通常需要對需要使用它們的每個程序進行重大的重編碼。
要查看寬度參數的效果,請看下面的代碼:
>>> sample=12345.6789
>>> print(
... f"(1) |{sample:.2f}|",
... f"(2) |{sample:1.2f}|",
... f"(3) |{sample:8.2f}|",
... f"(4) |{sample:12.2f}|",
... sep="\n",
... )
(1) |12345.68|
(2) |12345.68|
(3) |12345.68|
(4) | 12345.68|
在這四個結果中,精度設置為.2f,這意味著所有數字都四舍五入保留兩位小數。因為處理的是數字,所以默認情況下會在左側用空格填充。您使用換行符(\n)作為值分隔符,以便將每個輸出打印在自己的行上。您還在每個數字之間用管道字符(|)顯示,以突出顯示填充效果。
在第一個結果中,未指定寬度,因此f字符串會自動為您處理,并將字符串的大小設置為包含小數點前的所有內容以及指定的兩位小數。
在第二個示例中,寬度太小,無法容納輸出,因此調整大小以使字符串適合。
在第三個示例中,寬度正好是所需的大小,因此沒有填充,再次得到相同的結果。
最后一個示例顯示了填充已應用到輸出中。寬度比所需寬度大四個字符,因此在字符串的開頭插入了四個空格。
除非您需要額外的填充,否則通常最好完全忽略寬度值,讓f字符串為您處理它。
注意:默認情況下,當您將字段寬度參數應用于字符串時,填充會放置在右側:
>>> f"|{"123.45":10}|"
'|123.45 |'
>>> f"|{123.45:10}|"
'| 123.45|'
如您所見,額外的空格已添加到字符串的右側,使其寬度達到10個字符。第二個示例顯示數字左側填充,但仍然為相同的10個字符。如果您為字符串指定了諸如.2f之類的精度參數,則會生成ValueError。字符串不理解精度。您將在本教程的后面學習如何使用帶有格式說明符的字符串。
您還可以控制填充的位置,如果需要的話。您可以在指定的寬度內左對齊、右對齊,甚至居中您的數據:
>>> sample=12345.6789
>>> print(
... f"(1) |{sample:<12,.2f}|",
... f"(2) |{sample:>12,.2f}|",
... f"(3) |{sample:^12,.2f}|",
... sep="\n",
... )
(1) |12,345.68 |
(2) | 12,345.68|
(3) | 12,345.68 |
要控制填充的位置,您可以使用小于號(<)、大于號(>)或插入符號(^)對齊選項。它們分別允許您將數字左對齊、右對齊和居中對齊在指定的寬度值內。
您可能已經注意到,只添加了三個空格字符,而不是之前看到的四個。這是因為通過在格式說明符中包含千位分隔符,您已經使用了額外的字符空間。
現在假設您想要使用填充,但更喜歡使用與迄今為止默認的空格不同的填充字符。為此,您可以在對齊選項之前添加您選擇的填充字符:
>>> sample=12345.6789
>>> print(
... f"(1) |{sample:*<12.2f}|",
... f"(2) |{sample:*>12.2f}|",
... f"(3) |{sample:*^12.2f}|",
... sep="\n",
... )
(1) |12345.68****|
(2) |****12345.68|
(3) |**12345.68**|
在這個例子中,您選擇使用星號(*)字符來填充您的數字,盡管您也可以使用其他任何字符。為此,您將星號添加到格式說明符中。您的數字被格式化為預期的兩位小數,并填充了適當數量的星號,以確保它是您想要的12個字符寬度。
到目前為止,您的每個示例中都使用了正數。隨時可以使用負數重新運行其中任何一個示例,您會看到負號會出現在它們旁邊。為了遵循通常的假設,即無符號數是正數,正數保持為無符號。
假設您想要對每個數字顯示一個符號,以突出或澄清,或者創建用于文件的固定長度記錄。為了強制顯示所有數字的符號,您將加號(+)選項添加到格式說明符中,如下所示:
>>> sample=-12345.68
>>> print(
... f"(1) |{sample:12,.2f}|",
... f"(2) |{sample:+12,.2f}|",
... f"(3) |{-sample:+12,.2f}|",
... sep="\n",
... )
(1) | -12,345.68|
(2) | -12,345.68|
(3) | +12,345.68|
這一次,您使用的數字是負數。在第一個示例中,當您使用12,.2f格式說明符時,負號會出現。第二個示例給出了相同的輸出,但您在格式說明符的開頭添加了一個加號。這種好處只有在第三個示例中對數字取反時才會顯現出來。格式說明符中的加號(+)選項現在強制在您的輸出中顯示加號。
注意:在計算中顯示結果為零的計算在計算中存在一個古老的問題。如果計算的一部分涉及負數,可能會顯示出令人討厭的結果:
>>> result=(5 * 0) / (-4 + 2)
>>> print(
... f"(1) {result:12.1g}",
... f"(2) {result:+12.1f}",
... sep="\n",
... )
(1) -0
(2) -0.0
雖然邏輯告訴您答案是無符號零,但Python等大多數語言堅持顯示負號。這是由于浮點數在內存中的表示方式導致的。無論您是否四舍五入到小數位數、有效數字,或者在格式說明符中使用加號,這都會發生。通常,這是您不想看到的東西。
幸運的是,PEP 682提供了一個解決方案,允許您從零中刪除煩人的負號(-)。為此,您可以使用如下所示的z選項:
>>> print(
... f"(1) {result:z12.1g}",
... f"(2) {result:z12.1f}",
... sep="\n",
... )
(1) 0
(2) 0.0
正如您所看到的,負號現在消失了,您使事情看起來更整潔了。
您現在知道如何處理圍繞四舍五入數字顯示的一些復雜性。您仍然有一些有趣的事情要學習,但在繼續之前,現在是時候再次動動腦筋了。為什么不看看您是否能解決以下任務?
任務4a:使用樣本=-12345.6789,請嘗試編寫一行代碼以生成所示的輸出。輸出應為左對齊,寬度為12個字符,精確到兩位小數。不要忘記命令分隔符,并包括所有的零:
sample=-12345.6789
print(f"{sample:12,.2f}")
print(f"{-sample:12,.2f}")
任務4b:更新您之前的輸出,使其顯示如下所示。它與之前的輸出非常相似,只是加號(+)被替換為一個空格。理想情況下,您應該對兩個輸出使用類似的格式說明符。如果需要幫助,請記得查閱Python文檔:
sample=-12345.6789
print(f"{sample:12,.2f}")
print(f"{' ' + str(-sample):12,.2f}")
任務5:從result=5 * 3開始,然后嘗試生成所示的輸出,而不需要將字面上的小數點符號(.)編碼到f字符串的末尾。相反,使用適當的格式說明符語法編碼尾隨小數點:
result=5 * 3
print(f"By default, the result is displayed like this: {result}")
print(f"However, some people love trailing decimal points like this: {result}.")
任務6:從三個變量開始,customer_id="C123456",amount1=12.34和amount2=56.78,然后嘗試生成如下所示的固定長度記錄:
customer_id="C123456"
amount1=12.34
amount2=56.78
print(f"{customer_id}{amount1:08.2f}{amount2:08.2f}")
現在您已經學會了如何四舍五入日常數字,并有機會練習您的技能,現在是時候看看如何格式化大數字和小數字,以及難以想象的復數了。
當您想簡潔地書寫非常大或非常小的數字時,通常會使用科學記數法。Python 和許多其他編程語言一樣,使用 E 符號來顯示科學記數法,如下所示:
在上圖中,您可以看到兩個使用科學符號格式化數字的示例。第一個使用了傳統的數學表示法,而第二個則使用了 Python 的表示法。
如果你知道可以使用格式說明符用科學記數法顯示數字,一定不會感到驚訝。下面是操作方法:
>>> f"{1234.56789:.2e}"
'1.23e+03'
>>> f"{0.00012345:.3e}"
'1.234e-04'
您可能用于以科學計數法格式化數字的常見格式說明符是小寫字母(e)表示類型。它在顯示中使用小寫字母e。
在第一個示例中,因為您設置了精度為.2e,所以您的字符串將以科學計數法顯示數字,并四舍五入到兩位小數。您也可以添加一個寬度值。與之前一樣,這只是在必要時填充結果以適應寬度。
在第二個示例中,您朝著另一個方向前進,并顯示一個非常小的數字。因此,科學計數法將指數提高到-04。這次,您使用了.3e來將結果顯示到三位小數。
與您通過格式說明符傳遞的所有數字一樣,格式說明符僅是一個顯示工具。所有計算應使用原始數字以保持準確性。
您還可以使用格式說明符處理復數。復數在工程和物理學中廣泛用于解決與振蕩相關的方程。例如,它們可以作為傅立葉變換的一部分來從真實傳輸中去除噪聲頻率。
復數由實部和虛部組成,其中虛部是負一的平方根的倍數。它們通常寫成a+bi的形式,其中a稱為實部,b稱為虛部。
注:Python 用字母 j 代替 i 表示虛部。
盡管復數的性質有些抽象,但您會很高興知道格式指定器已經涵蓋了復數:
>>> value=3.474 + 2.323j
>>> print(
... f"The complex number {value} is formed",
... f"from the real part {value.real:.2f},",
... f"the imaginary part {value.imag:.1f},",
... f"and is approximately {value:.0f}.",
... sep="\n",
... )
The complex number (3.474+2.323j) is formed
from the real part 3.47,
the imaginary part 2.3,
and is approximately 3+2j.
正如您所看到的,您可以使用.f-字符串表達式中的.real和.imag屬性訪問復數的實部和虛部。一旦您有了這些,您就可以像格式化任何其他數字一樣格式化它們。您還可以直接將格式說明符應用于整個復數來一次性格式化它。
在上面的示例中,.2f將實部格式化為兩位小數,然后.1f將虛部格式化為一位小數。最后,.0f將完整的數字格式化為零位小數。
很快,您將遠離使用f-字符串中的基本方法來四舍五入數字,并學習它們可以以其他方式使用的方法。在您開始之前,現在是時候進行另一個挑戰了。
任務7:使用value=13579+0.0245j,請嘗試編寫一行代碼以生成下面所示的輸出:
value=13579 + 0.0245j
print(f"The real part is {value.real:.2e} and the imaginary part {value.imag:.2e}.")
Python中的浮點類型限制您將數字存儲為64位。這意味著如果您的任何數字超過此大小,則無法準確表示。下面的代碼顯示了一個例子:
f"{(10000000000000 / 3)}"
'3333333333333.3335'
精確的答案是一個無限數量的重復數字3。如您所見,由于空間限制,一個末尾的5已經出現了。
您可能會認為使用格式說明符.2f將輸出顯示為兩位小數會解決問題,但在背景中仍然存在不準確性。格式說明符僅將其數據四舍五入以進行顯示。它們不截斷數據。
例如,考慮以下計算:
f"{(10000000000000 / 3) + 0.6666}"
'3333333333334.0'
結果不僅顯示了不準確性仍然存在,而且錯誤現在已經進入了結果的整數部分。進一步的計算將使這個問題更加復雜,并導致最終結果更加不準確。
盡管圍繞計算機上的浮點數算術的精度問題是其設計的固有部分,但如果您需要精度保證,那么您應該考慮使用內置的decimal模塊。Decimal對象提供了比內置的浮點類型更多的浮點數算術控制,因為它們允許您以一致的精度進行計算,并集中設置該精度。
要查看這個優點如何發揮作用,請查看下面的代碼:
from decimal import Decimal as D
from decimal import getcontext
getcontext().prec=4
f"£{float("0.1") + float("0.1") + float("0.1")}"
'£0.30000000000000004'
f"£{D("0.1") + D("0.1") + D("0.1")}"
'£0.3'
decimal模塊是Python標準庫的一部分,所以您不需要安裝它。但是,為了訪問您將實例化對象的Decimal類,您仍然必須導入它。通過將Decimal與其別名D一起導入,您可以在創建實例時使用該別名,從而編寫更簡潔的代碼。
您還導入了getcontext()函數。當您在代碼中使用Decimal對象時,它們的許多關鍵屬性由它們的上下文對象集中管理。getcontext()函數為您獲取這個。然后,您使用其.prec屬性設置Decimal對象的精度。這定義了每個Decimal將包含的有效數字的數量。Decimal實例會四舍五入以適應其精度。
看看上面代碼的輸出。當您使用浮點數時,表示誤差會出現。但是,當使用Decimal實例時,它卻看不到。而且,這個錯誤永遠不會再次出現。
這里的要點是,對于非常高的精度,您應該在應用格式說明符之前將字符串轉換為十進制,而不是浮點數。這樣可以防止錯誤傳播到您的計算中,因為超出指定精度的任何內容都將被安全地刪除。此外,小數的默認精度為28位,而浮點數只有約16位。
注意:您可能會想知道是否應該簡單地使用Python的內置round()函數來四舍五入每個浮點值。這確實是消除表示錯誤的一種替代方法,但是decimal模塊使用的上下文對象使得在一個地方更改每個數字的精度更容易。該庫還提供了Decimal.quantize()方法,以便您更精細地控制如何對Decimal對象進行舍入。
為了幫助您決定使用哪個精度值,請考慮守護數字的概念。假設您正在執行涉及貨幣的計算。盡管結果可能包含兩位小數,但中間計算應使用四位小數以防止舍入影響最終結果。您應始終使用比要顯示的小數位數多兩個守護數字。
您可以通過組合精度和格式說明符來引入守護數字。格式說明符可以應用于Decimal對象,方式與應用于浮點數相同:
getcontext().prec=4
f"£{D("0.10001") + D("0.20001"):.2f}"
'£0.30'
首先,您要將兩個數字相加,而這兩個數字的原始形式包含微小的誤差。由于您已將上下文精度設置為 4 位有效數字,因此在將每個字符串轉換為十進制對象時,這些誤差將被消除。計算開始后,格式說明符會將顯示的答案四舍五入到小數點后兩位。
注意:盡管decimal模塊提供了出色的浮點支持,但它仍然無法解決與浮點數相關的基礎舍入問題。
看看下面顯示的Decimal對象:
D(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
您可能期望答案是0.1000,因為全局精度是4。忽略精度的原因是因為getcontext().prec屬性僅適用于表達式的結果,而不直接適用于浮點數。您可以強制應用精度,但代碼有點做作:
D(0.1) * D(1)
Decimal('0.1000')
通過乘以D(1),您再次應用了四個有效數字的精度。
在 Python 中,還有一些其他的方法可以將數字格式化為字符串,接下來我們將探討這些方法。
Python內置的format()函數是另一種生成格式化字符串的方法。該函數接受兩個參數:要格式化的值以及您已經學過的任何格式說明符。下面顯示了一些示例,其中包含它們的f-string等效項以供比較:
>>> format(-123.4567, "+9.2f")
' -123.46'
>>> f"{-123.456:+9.2f}"
' -123.46'
>>> format(0.125, ".2%")
'12.50%'
>>> f"{0.125:.2%}"
'12.50%'
正如您所見,format()函數使用與更現代的f-string相同的格式說明符迷你語言。您的第一個示例使用+9.2f來顯示表示帶符號浮點數的字符串,填充到9個字符并舍入為2位小數。然后,您使用.2%將數字顯示為百分比形式的兩位小數。
花點時間比較使用format()和使用f-string的代碼,您會發現f-string版本更緊湊,通常更易讀。
一個早期的字符串格式化方法,今天仍然有用處的是str.format()方法。要使用它,您需要在字符串中插入替換字段占位符,指定您希望數據顯示的位置。然后,您將格式說明符添加到占位符中,以指定數據的外觀方式。最后,您將要插入字符串的數據作為參數傳遞給.format(),順序與占位符相同。
下面的代碼示例說明了所有這些:
>>> opposite=1.234
>>> adjacent=5.678
>>> hypotenuse=(opposite**2 + adjacent**2) ** 0.5
>>> template="Opposite={:0.1f}, Adjacent={:0.2f}, Hypotenuse={:0.3f}"
>>> template.format(opposite, adjacent, hypotenuse)
'Opposite=1.2, Adjacent=5.68, Hypotenuse=5.811'
正如您所見,占位符使用傳遞給.format()方法的每個參數。盡管這不像f-string替代品那么可讀,但您仍然使用相同的迷你語言來定義格式。
在.format()中傳遞值的方式也可以通過關鍵字傳遞。當您將這些關鍵字添加到字符串的替換字段中時,當顯示字符串時,相應的值將被插入其中:
>>> template=(
... "Opposite={opposite:0.1f}, "
... "Adjacent={adjacent:0.2f}, "
... "Hypotenuse={hypotenuse:0.3f}"
... )
>>> template.format(
... hypotenuse=(1.234**2 + 5.678**2)**0.5,
... adjacent=5.678,
... opposite=1.234
... )
'Opposite=1.2, Adjacent=5.68, Hypotenuse=5.811'
在此版本中,您通過關鍵字將參數傳遞給.format()。注意,您傳遞的參數順序并不重要。只要關鍵字與格式說明符中花括號中的占位符匹配,Python就會相應地進行替換。
而不是將單獨的值作為關鍵字參數傳遞,您可以遵循一種常見的模式,該模式涉及Python字典:
>>> data={
... "opposite": 1.234,
... "adjacent": 5.678,
... "hypotenuse": (1.234**2 + 5.678**2) ** 0.5,
... }
>>> template=(
... "Opposite={opposite:0.1f}, "
... "Adjacent={adjacent:0.2f}, "
... "Hypotenuse={hypotenuse:0.3f}"
... )
>>> template.format(**data)
'Opposite=1.2, Adjacent=5.68, Hypotenuse=5.811'
在代碼中,您使用解包運算符(**)將字典數據傳遞給.format()。這會將字典中的每個鍵作為單獨的命名參數傳遞,并將其每個值作為命名參數的值。
正如您所見,這段代碼越來越接近您使用f-strings的語法。您可以將此方法提升到一個新的水平,并創建自己的數字格式化模板:
>>> num="{:{align}{width}.{precision}f}"
>>> print(
... num.format(
... 123.236, align="<", width=8, precision=2
... )
... )
123.24
這次,您通過將要格式化的數字傳遞給.format()以及一組傳遞給.format()的命名參數來構造格式說明符。這些參數應用于您的num模板,然后用于格式化您的數字。
當您使用.format()時,還可以在運行時動態定義格式說明符。假設您有幾個單詞希望填充到比其長度長四個字符的寬度。下面的代碼顯示了如何實現這一點:
>>> text="Python is cool"
>>> padded_words=[
... "{word:*^{length}}".format(word=word, length=len(word) + 4)
... for word in text.split()
... ]
>>> padded_words
['**Python**', '**is**', '**cool**']
再次,您構造了格式說明符,其中包含您將從.format()中接收的參數的名稱。要格式化的單詞分配給word,而動態計算的寬度分配給length。您通過在格式說明符中嵌套精度替換字段{length}來實現此目的。星號(*)定義了要使用的填充字符,插入號(^)符號確保輸出居中。
使用列表推導式創建了padded_words列表。在text變量的內容上調用了.split()方法,該方法
通過其空格字符分隔出原始字符串,并產生一個包含其三個單詞的列表。然后,for循環遍歷其中的每一個,并將它們傳遞給.format()。
當每個單詞由.format()接收時,它的值被分配給word變量,其長度加上四個字符被分配給length變量。然后,這些變量應用于格式說明符,以在padded_words中生成格式化版本。
如果您需要編寫將在國際范圍內使用的代碼,您需要確保數字按照它們所在國家/地區的語言環境進行格式化。這將確保您的數字和日期按照當地的約定格式化,以便正確理解。為了在代碼中支持國際化,您可以使用Python的locale模塊。
locale模塊允許您指定標準格式,如千位分隔符、貨幣符號等。通常情況下,您不需要在計算機上顯式設置這些格式,因為默認情況下會使用您的操作系統設置。但是,如果您希望確保您的代碼使用特定的語言環境運行,您可以顯式設置它。
您可以使用locale.getlocale()函數找到計算機當前使用的語言環境:
>>> import locale
>>> locale.getlocale()
('English_United Kingdom', '1252')
用于運行此代碼的計算機正在使用English_United Kingdom語言環境。1252是Windows在對每個英文字符進行編碼時使用的字符編碼。每個符號在內存中占據一個字節。運行代碼以查看您的語言環境結果。
如果您想要根據計算機上的語言環境格式化數字,請在格式說明符中使用n演示類型:
>>> f"{-1234.567:n}"
'-1234.57'
>>> f"{-1234.567:.2f}"
'-1234.57'
正如您所見,在使用語言環境('English_United Kingdom', '1252')的計算機上,n格式說明符等效于使用.2f作為格式說明符。這個語言環境規定使用句點(.)作為小數點,而負號放置在數字的左側。
要真正欣賞n的作用,您需要在一系列語言環境中運行它。幸運的是,locale模塊提供了setlocale()函數,允許您這樣做。只要您的操作系統支持您感興趣的語言環境,您就可以更改數字的顯示方式:
>>> sample_locales=[
... ("USA", "en_US.UTF-8"),
... ("Poland", "pl_PL.UTF-8"),
... ("UK", "en_GB.UTF-8"),
... ("Czech Republic", "cs_CZ.UTF-8"),
... ("Korea", "ko_KR.UTF-8"),
... ("Germany", "de_DE.UTF-8"),
... ("France", "fr_FR.UTF-8"),
... ]
>>> for name, loc in sample_locales:
... _=locale.setlocale(category=locale.LC_ALL, locale=loc)
... print(
... f"{name} uses",
... f"{1234.567:n} and",
... f"{-1234.567:n}",
... )
...
在這里,您創建了一個包含每個國家和語言環境名稱的元組列表。每個語言環境值的格式為"language_territory.codeset"。因此,"en_US.UTF-8"指定了使用美國英語,并使用UTF-8標準對每個字符進行編碼。
您的for循環遍歷sample_locales中的每個元組,并將其傳遞給set_locale()函數的locale參數。這將在計算機上設置語言環境。您還將category參數設置為LC_ALL,以確保將語言環境應用于所有類別,包括數字、日期和貨幣。最后,您攔截了函數返回的語言環境名稱,以防止它被REPL打印出來。
一旦計算機設置了新的語言環境,print()函數就會向您顯示樣本中每個國家中正數和負數的顯示方式。再次,所有內容都舍入為兩位小數。
注意:您可能已經注意到,英國語言環境的數字現在有了分隔符。這是因為您已將語言環境設置為en_GB.UTF-8,而不是Windows默認的語言環境。
如果您需要對數字輸出的格式進行更多控制,locale提供了format_string()函數,該
函數使用類似于您之前學到的格式說明符代碼:
>>> for name, loc in sample_locales:
... _=locale.setlocale(category=locale.LC_ALL, locale=loc)
... print(
... f"{name} uses --> {locale.format_string(
... f="%10.2e", val=-123456.789, grouping=True
... )}"
... )
...
在這里,您以本地形式顯示了每個數字的科學計數法。為此,您將f="%10.2e"傳遞給format_string()。使用此函數時,必須在格式之前使用字符串格式化運算符符號(%)。您還將grouping參數設置為True,以確保應用了千位分隔符。
注意:當您使用形式"%10.2e"定義格式時,您使用的是類似但不完全相同的格式語言,與更現代的格式說明符使用的語言不同。這次,您使用的是舊式的printf風格字符串格式化。
如果要顯示貨幣,可以使用locale.currency()函數:
>>> for name, loc in sample_locales:
... _=locale.setlocale(category=locale.LC_ALL, locale=loc)
... print(
... f"{name} uses",
... f"{locale.currency(val=123456.789, grouping=True)} and",
... f"{locale.currency(val=-123456.789, grouping=True)}",
... )
...
在這里,您可以看到在樣本中的每個國家中如何顯示不同的貨幣。您在currency()中使用了val和grouping參數,方式與之前在format_string()中使用的方式相同。
這就是全部內容,您已經完成了。現在您已經對Python允許您在字符串中舍入數字的主要方法有了扎實的了解。
在本教程中,您學習了很多內容,希望這些內容既有趣又具有挑戰性。現在您知道了如何使用 Python 的格式規范迷你語言,以標準方式舍入和顯示浮點數和十進制對象。
您還知道了如何處理科學數和復數。您還了解了在字符串中對數字進行四舍五入的一些舊方法,并看到了 f-string 語法的革命性意義。你甚至還學會了如何在字符串中對數字進行國際格式化。
現在,你已經對數字格式化有了全面的了解,應該進一步嘗試并考慮深入研究 f 字符串和支持它們的格式規范迷你語言。你還有很多東西要學。
月26日任務
4.5/4.6 磁盤格式化
4.7/4.8 磁盤掛載
4.9 手動增加swap空間
磁盤格式化
查看系統支持的文件系統
系統支持的文件系統類型 [root@centos7 ~]# cat /etc/filesystems xfs ext4 ext3 ext2 nodev proc nodev devpts iso9660 vfat hfs hfsplus * centos7 系統默認的文件系統格式是 xfs, centos6.x版本為ext4,再之前就是ext3/2...
格式化新分區
格式化分區類型為ext2,塊大小為4096字節(即4K),預留磁盤空間為5%。可以通過參數(單個或多個結合)設置來修改!
[root@localhost ~]# mke2fs /dev/sdb5 mke2fs 1.42.9 (28-Dec-2013) 文件系統標簽=OS type: Linux 塊大小=4096 (log=2) 分塊大小=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 65536 inodes, 262144 blocks 13107 blocks (5.00%) reserved for the super user 第一個數據塊=0 Maximum filesystem blocks=268435456 8 block groups 32768 blocks per group, 32768 fragments per group 8192 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: 完成 正在寫入inode表: 完成 Writing superblocks and filesystem accounting information: 完成 [root@localhost ~]# blkid /dev/sdb5 /dev/sdb5: UUID="c8ac98dc-9794-44ee-a29d-90e13d405175" TYPE="ext2"
[root@localhost ~]# mke2fs -t ext4 /dev/sdb5 .... information: 完成 [root@localhost ~]# blkid /dev/sdb5 /dev/sdb5: UUID="f98f1f5e-bb4a-4242-a1f4-7f83119bcb82" TYPE="ext4"
系統塊大小默認為4096字節 (根據所存儲數據大小特性,調整block大小,可以優化性能,一般來說保存默認即可)
[root@localhost ~]# mke2fs -t ext4 -b 2048 /dev/sdb5 mke2fs 1.42.9 (28-Dec-2013) 文件系統標簽=OS type: Linux 塊大小=2048 (log=1) # 塊大小已被修改為2048字節 分塊大小=2048 (log=1) ...... information: 完成
[root@localhost ~]# blkid /dev/sdb5 /dev/sdb5: UUID="ec2d49ca-08f6-45dc-9e31-cfe55a997f8e" TYPE="ext4" [root@localhost ~]# mke2fs -t ext4 -m 1 /dev/sdb5 mke2fs 1.42.9 (28-Dec-2013) 文件系統標簽=OS type: Linux 塊大小=4096 (log=2) 分塊大小=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 65536 inodes, 262144 blocks 2621 blocks (1.00%) reserved # 預留設置了1% ...... information: 完成
[root@localhost ~]# mke2fs -t ext4 -i 8192 /dev/sdb5 mke2fs 1.42.9 (28-Dec-2013) 文件系統標簽=OS type: Linux 塊大小=4096 (log=2) 分塊大小=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 131072 inodes, 262144 blocks # 1個inode對于2個blocks即8192字節 ...... information: 完成
使用 man mke2fs 查看命令具體使用
2. mkfs.ext4/xfs命令
mkfs.抬頭的命令有以下幾種
[root@localhost ~]# mkfs. mkfs.btrfs mkfs.ext2 mkfs.ext4 mkfs.xfs mkfs.cramfs mkfs.ext3 mkfs.minix
主要介紹下mkfs.ext4和mkfs.xfs
[root@localhost ~]# mkfs.ext4 /dev/sdb5 mke2fs 1.42.9 (28-Dec-2013) 文件系統標簽=OS type: Linux 塊大小=4096 (log=2) 分塊大小=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 65536 inodes, 262144 blocks 13107 blocks (5.00%) reserved for the super user 第一個數據塊=0 Maximum filesystem blocks=268435456 8 block groups 32768 blocks per group, 32768 fragments per group 8192 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: 完成 正在寫入inode表: 完成 Creating journal (8192 blocks): 完成 Writing superblocks and filesystem accounting information: 完成
[root@localhost ~]# mkfs.xfs /dev/sdb5 mkfs.xfs: /dev/sdb5 appears to contain an existing filesystem (ext4). mkfs.xfs: Use the -f option to force overwrite. # 對于已經設置過文件系統類型的磁盤需要執行-f參數強制格式化 [root@localhost ~]# mkfs.xfs -f /dev/sdb5 meta-data=/dev/sdb5 isize=512 agcount=4, agsize=65536 blks=sectsz=512 attr=2, projid32bit=1=crc=1 finobt=0, sparse=0 data=bsize=4096 blocks=262144, imaxpct=25=sunit=0 swidth=0 blks naming=version 2 bsize=4096 ascii-ci=0 ftype=1 log=internal log bsize=4096 blocks=2560, version=2=sectsz=512 sunit=0 blks, lazy-count=1 realtime=none extsz=4096 blocks=0, rtextents=0
[root@localhost ~]# blkid /dev/sdb5 /dev/sdb5: UUID="6f2aa21a-3af6-455b-91a6-277088815c98" TYPE="xfs"
格式化未分區磁盤
不僅可以對分過區的磁盤進行格式化操作,也可以直接對未分區的磁盤進行格式化!
[root@localhost ~]# mkfs.xfs -f /dev/sdb meta-data=/dev/sdb isize=512 agcount=4, agsize=655360 blks=sectsz=512 attr=2, projid32bit=1=crc=1 finobt=0, sparse=0 data=bsize=4096 blocks=2621440, imaxpct=25=sunit=0 swidth=0 blks naming=version 2 bsize=4096 ascii-ci=0 ftype=1 log=internal log bsize=4096 blocks=2560, version=2=sectsz=512 sunit=0 blks, lazy-count=1 realtime=none extsz=4096 blocks=0, rtextents=0 [root@localhost ~]# blkid /dev/sdb /dev/sdb: UUID="018febb7-642f-4935-b8ae-52d39118a24d" TYPE="xfs"
磁盤分區掛載
掛載命令:mount
Usage: mount 磁盤分區 掛載點
掛載完成后就可以使用df -h命令看到掛載的分區,也可以使用mount命令查看磁盤的文件系統類型。
# 掛載前 [root@localhost ~]# df -h 文件系統 容量 已用 可用 已用% 掛載點 /dev/sda3 18G 1.2G 17G 7% / devtmpfs 479M 0 479M 0% /dev tmpfs 489M 0 489M 0% /dev/shm tmpfs 489M 6.7M 482M 2% /run tmpfs 489M 0 489M 0% /sys/fs/cgroup /dev/sda1 197M 109M 88M 56% /boot tmpfs 98M 0 98M 0% /run/user/0 # 執行mount命令掛載后 [root@localhost ~]# mount /dev/sdb /mnt [root@localhost ~]# df -h 文件系統 容量 已用 可用 已用% 掛載點 /dev/sda3 18G 1.2G 17G 7% / devtmpfs 479M 0 479M 0% /dev tmpfs 489M 0 489M 0% /dev/shm tmpfs 489M 6.7M 482M 2% /run tmpfs 489M 0 489M 0% /sys/fs/cgroup /dev/sda1 197M 109M 88M 56% /boot tmpfs 98M 0 98M 0% /run/user/0 /dev/sdb 10G 33M 10G 1% /mnt
mount常用參數
掛載配置文件 /etc/fstab
[root@centos7 ~]# cat /etc/fstab # # /etc/fstab # Created by anaconda on Thu Aug 31 05:17:14 2017 # # Accessible filesystems, by reference, are maintained under '/dev/disk' # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # UUID=5ee3eb67-81a1-4064-83fc-fbf79c808c7a / xfs defaults 0 0 UUID=5671cec2-24c1-4553-8c96-00057ce308a6 /boot xfs defaults 0 0 UUID=1f8c12e3-4ff7-46d5-a720-1be96686adcd swap swap defaults 0 0 第一列:掛載的文件系統盤名或UUID 第二列:掛載點 第三列:分區的文件系統類型 第四列:掛載選項 第五列:是否備份; 第六列:是否檢測磁盤優先級0-2,0不檢測,2優先級比1高
卸載命令:umount
Usage: umount 磁盤分區/掛載點
[root@localhost mnt]# umount /dev/sdb umount: /mnt:目標忙。 (有些情況下通過 lsof(8) 或 fuser(1) 可以 找到有關使用該設備的進程的有用信息) [root@localhost mnt]# cd [root@localhost ~]# umount /dev/sdb
[root@localhost ~]# cd /mnt/ [root@localhost mnt]# umount -l /dev/sdb [root@localhost mnt]# df -h 文件系統 容量 已用 可用 已用% 掛載點 /dev/sda3 18G 1.2G 17G 7% / devtmpfs 479M 0 479M 0% /dev tmpfs 489M 0 489M 0% /dev/shm tmpfs 489M 6.7M 482M 2% /run tmpfs 489M 0 489M 0% /sys/fs/cgroup /dev/sda1 197M 109M 88M 56% /boot tmpfs 98M 0 98M 0% /run/user/0
實用技巧
手動增加swap空間
# /dev/zero是系統的一個特殊設備,它輸出的是空數據 [root@localhost ~]# dd if=/dev/zero of=/tmp/newdisk bs=1M count=100 記錄了100+0 的讀入 記錄了100+0 的寫出 104857600字節(105 MB)已復制,24.364 秒,4.3 MB/秒 # 查看磁盤大小 [root@localhost ~]# du -sh /tmp/newdisk 100M /tmp/newdisk
2. 格式化空磁盤
[root@localhost ~]# mkswap -f /tmp/newdisk 正在設置交換空間版本 1,大小=102396 KiB 無標簽,UUID=8a12dd8f-f4ff-412f-a6cf-fdca4aacba37
3. 將新磁盤加到swap空間上去
[root@localhost ~]# free -m total used free shared buff/cache available Mem: 976 115 604 6 257 687 Swap: 2047 0 2047 [root@localhost ~]# swapon /tmp/newdisk swapon: /tmp/newdisk:不安全的權限 0644,建議使用 0600。 # 提示警告,但是也已經成功增容 [root@localhost ~]# free -m total used free shared buff/cache available Mem: 976 115 604 6 257 687 Swap: 2147 0 2147 # 最好執行權限修改后再執行swapon [root@localhost ~]# chmod 0600 /tmp/newdisk
如何刪除
刪掉新添加的磁盤空間