在 Python 3.6 之前,字符串格式化方法主要有兩種:%格式化 和 str.format()。下面我們簡單看下它們的使用方法,以及局限。
1 %-格式化
% 格式化方法從 Python 剛開始時就存在了,堪稱「一屆元老」,但是 Python 官方文檔中並不推薦這種格式化方式:
這里描述的格式化操作容易表現出各種問題,導致許多常見錯誤(例如無法正確顯示元組和字典)。
使用較新的格式化字符串文字或 str.format() 可以有助於避免這些錯誤。這些替代方案還提供了更強大,靈活和可擴展的格式化文本方法。
1.1 如何使用 %格式化
一般使用方式,要插入多個變量的話,必須使用元組:
>>> name = "hoxis" >>> age = 18 >>> "hello, %s. you are %s ?" %(name, age) 'hello, hoxis. you are 18 ?'
1.2 %格式化的缺陷
上面的代碼示例看起來還能讀,但是,一旦開始使用多個參數和更長的字符串,你的代碼將很快變得不那么容易閱讀:
>>> name = "hoxis" >>> age = 18 >>> country = "China" >>> hair = "black" >>> "hello, %s. you are %s ?. Your country is %s, and your hair is %s" %(name, age, country,hair) 'hello, hoxis. you are 18 ?. Your country is China, and your hair is black'
可以看出,這種格式化並不是很好,因為它很冗長並且容易導致錯誤,比如沒有正確顯示元組或字典。
不過還好我們還有 str.format()。
2 str.format()
Python 2.6 中引入了 str.format() 格式化方法:https://docs.python.org/3/library/stdtypes.html#str.format。
2.1 str.format() 的使用
str.format() 是對 %格式化 的改進,它使用普通函數調用語法,並且可以通過 __format__() 方法為對象進行擴展。
使用 str.format() 時,替換字段用大括號進行標記:
>>> "hello, {}. you are {}?".format(name,age) 'hello, hoxis. you are 18?'
並且可以通過索引來以其他順序引用變量:
>>> "hello, {1}. you are {0}?".format(age,name) 'hello, hoxis. you are 18?'
或者可以這樣:
>>> "hello, {name}. you are {age1}?".format(age1=age,name=name) 'hello, hoxis. you are 18?'
從字典中讀取數據時還可以使用 **:
>>> person = {"name":"hoxis","age":18} >>> "hello, {name}. you are {age}?".format(**person) 'hello, hoxis. you are 18?'
確實,str.format() 比 %格式化高級了一些,但是它還是有自己的缺陷。
2.2 str.format() 的缺陷
在處理多個參數和更長的字符串時仍然可能非常冗長,麻煩!看看這個:
>>> "hello, {}. you are {} ?. Your country is {}, and your hair is {}".format(name, age, country,hair) 'hello, hoxis. you are 18 ?. Your country is China, and your hair is black'
3 f-Strings
還好,現在我們有了 f-Strings,它可以使得字符串格式化更加容易。
f-strings 是指以 f 或 F 開頭的字符串,其中以 {} 包含的表達式會進行值替換。
下面從多個方面看下 f-strings 的使用方法,看完后,我相信你會對「人生苦短,我用 Python」有更深地贊同~
3.1 f-Strings 使用方法
>>> name = 'hoxis' >>> age = 18 >>> f"hi, {name}, are you {age}" 'hi, hoxis, are you 18' >>> F"hi, {name}, are you {age}" 'hi, hoxis, are you 18'
是不是很簡潔?!還有更牛叉的!
因為 f-strings 是在運行時計算的,那么這就意味着你可以在其中放置任意合法的 Python 表達式,比如:
- 運算表達式
>>> f"{ 2 * 3 + 1}" '7'
- 調用函數
還可以調用函數:
>>> def test(input): ... return input.lower() ... >>> name = "Hoxis" >>> f"{test(name)} is handsome." 'hoxis is handsome.'
也可以直接調用內置函數:
>>> f"{name.lower()} is handsome." 'hoxis is handsome.'
- 在類中使用
>>> class Person: ... def __init__(self,name,age): ... self.name = name ... self.age = age ... def __str__(self): ... return f"{self.name} is {self.age}" ... def __repr__(self): ... return f"{self.name} is {self.age}. HAHA!" ... >>> hoxis = Person("hoxis",18) >>> f"{hoxis}" 'hoxis is 18' >>> f"{hoxis!r}" 'hoxis is 18. HAHA!' >>> print(hoxis) hoxis is 18 >>> hoxis hoxis is 18. HAHA!
- 多行 f-string
>>> name = 'hoxis' >>> age = 18 >>> status = 'Python' >>> message = { ... f'hi {name}.' ... f'you are {age}.' ... f'you are learning {status}.' ... } >>> >>> message {'hi hoxis.you are 18.you are learning Python.'}
這里需要注意,每行都要加上 f 前綴,否則格式化會不起作用:
>>> message = { ... f'hi {name}.' ... 'you are learning {status}.' ... } >>> message {'hi hoxis.you are learning {status}.'}
4 速度對比
其實,f-string 里的 f 也許可以代表 fast,它比 %格式化方法和 str.format() 都要快:
from timeit import timeit print(timeit("""name = "hoxis" age = 18 '%s is %s.' % (name, age)""", number = 10000)) print(timeit("""name = "hoxis" age = 18 '{} is {}.'.format(name, age)""", number = 10000)) print(timeit("""name = "hoxis" age = 18 f'{name} is {age}.'""", number = 10000))
運行結果:
$ python3.6 fstring.py
0.002238000015495345
0.004068000009283423
0.0015349999885074794
很明顯,f-string 是最快的,並且語法是最簡潔的,是不是迫不及待地要試試了?
5 注意事項
5.1 引號的處理
可以在字符串中使用各種引號,只要保證和外部的引號不重復即可。
以下使用方式都是沒問題的:
>>> f"{'hoxis'}" 'hoxis' >>> f'{"hoxis"}' 'hoxis' >>> f"""hoxis""" 'hoxis' >>> f'''hoxis''' 'hoxis'
那如果字符串內部的引號和外部的引號相同時呢?那就需要 \ 進行轉義:
>>> f"You are very \"handsome\"" 'You are very "handsome"'
5.2 括號的處理
若字符串中包含括號 {},那么你就需要用雙括號包裹它:
>>> f"{{74}}" '{74}' >>> f"{{{74}}}" '{74}'
可以看出,使用三個括號包裹效果一樣。
當然,你可以繼續增加括號數目,看下有什么其他效果:
>>> f"{{{{74}}}}" '{{74}}' >>> f"{{{{{74}}}}}" '{{74}}' >>> f"{{{{{{74}}}}}}" '{{{74}}}'
額,那么多括號,看着有點暈了...
5.3 反斜杠
上面說了,可以用反斜杠進行轉義字符,但是不能在 f-string 表達式中使用:
>>> f"You are very \"handsome\"" 'You are very "handsome"' >>> f"{You are very \"handsome\"}" File "<stdin>", line 1 SyntaxError: f-string expression part cannot include a backslash
你可以先在變量里處理好待轉義的字符,然后在表達式中引用變量:
>>> name = '"handsome"' >>> f'{name}' '"handsome"'
5.4 注釋符號
不能在表達式中出現 #,否則會報出異常;
>>> f"Hoxis is handsome # really" 'Hoxis is handsome # really' >>> f"Hoxis is handsome {#really}" File "<stdin>", line 1 SyntaxError: f-string expression part cannot include '#'
總結
經過以上的講解,是不是發現 f-string 非常簡潔實用、可讀性高,而且不易出錯,可以嘗試切換到 f-string 嘍~
f-string 也體現出了 Python 的奧義:
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
作者:劉哈哈
鏈接:https://zhuanlan.zhihu.com/p/39128162
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
