從python3.6開始,引入了新的字符串格式化方式,f-字符串. 這使得格式化字符串變得可讀性更高,更簡潔,更不容易出現錯誤並且速度也更快.html
在本文後面,會詳細介紹f-字符串的用法. 在此以前,讓咱們先來複習一下python中字符串格式化的方法.python
在python3.6以前,咱們有兩種方式能夠用來格式化字符串.web
首先複習一下這兩種方式的使用方法以及其短板.express
這種方式算是第0代字符串格式化的方法,不少語言都支持相似的字符串格式化方法. 在python的文檔中,咱們也常常看到這種方式.編程
可是!!! BUT!!!併發
佔位符+%的方式並非python推薦的方式.編輯器
❝Note The formatting operations described here exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly). Using the newer formatted string literals, the str.format() interface, or template strings may help avoid these errors. Each of these alternatives provides their own trade-offs and benefits of simplicity, flexibility, and/or extensibility.(Python3 doc)ide
❞
文檔中也說了,這種方式對於元組等的顯示支持的不夠好. 並且很容易產生錯誤.函數
並且不符合python代碼簡潔優雅的人設...flex
「如何使用佔位符+%的方式」
若是你接觸過其餘的語言,這種方式使用起來會有一種詭異的親切感,這種親切感會讓你抓狂,心裏會暗暗的罵上一句,艹,又是這德行...(這句不是翻譯,是個人我的感受,歷來都記不住那麼多數據類型的關鍵字...)
In [1]: name='Eric'
In [2]: 'Hello,%s'%name
Out[2]: 'Hello,Eric'
若是要插入多個變量的話,就必須使用元組.像這樣
In [3]: name='Eric'
In [4]: age=18
In [5]: 'Hello %s,you are %d.'%(name,age)
Out[5]: 'Hello Eric,you are 18.'
「爲何說佔位符+%的方式不是最好的辦法(我的認爲是這種方式是一種最操蛋的操做)」
上面有少許的變量須要插入到字符串的時候,這種辦法還行. 可是一旦有不少變量須要插入到一個長字符串中...好比...
In [6]: first_name = "Eric"
...: last_name = "Idle"
...: age = 74
...: profession = "comedian"
...: affiliation = "Monty Python"
In [7]: "Hello, %s %s. You are %s. You are a %s. You were a member of %s." % (first_name, last_name, age, profession, affiliation)
Out[7]: 'Hello, Eric Idle. You are 74. You are a comedian. You were a member of Monty Python.'
像上面這個例子,代碼可讀性就不好了.(對讀和寫的人都是一種折磨...)
在python2.6以後,引入了str.format()函數,能夠用來進行字符串的格式化. 它經過調用對象的__format__()方法(PEP3101中定義)來將對象轉化成字符串.
在str.format()方法中,經過花括號佔位的方式來實現變量插入.
In [8]: 'hello,{}. You are {}.'.format(name,age)
Out[8]: 'hello,Eric. You are 74.'
甚至能夠給佔位符加索引.
In [9]: 'hello,{1}. You are {0}.'.format(age,name)
Out[9]: 'hello,Eric. You are 74.'
若是要在佔位符中使用變量名的話,能夠像下面這樣
In [10]: person={'name':'Eric','age':74}
In [11]: 'hello,{name}. you are {age}'.format(name=person['name'],age=person['age'])
Out[11]: 'hello,Eric. you are 74'
固然對於字典來講的話,咱們可使用**
的小技巧.
In [15]: 'hello,{name}. you are {age}'.format(**person)
Out[15]: 'hello,Eric. you are 74'
str.format()方法對於%的方式來講已是一種很大的提高了. 可是這並非最好的方式.
「爲何format()方法不是最好的方式」 相比使用佔位符+%的方式,format()方法的可讀性已經很高了. 可是一樣的,若是處理含有不少變量的字符串的時候,代碼會變得很冗長.
>>> first_name = "Eric"
>>> last_name = "Idle"
>>> age = 74
>>> profession = "comedian"
>>> affiliation = "Monty Python"
>>> print(("Hello, {first_name} {last_name}. You are {age}. " +
>>> "You are a {profession}. You were a member of {affiliation}.") \
>>> .format(first_name=first_name, last_name=last_name, age=age, \
>>> profession=profession, affiliation=affiliation))
'Hello, Eric Idle. You are 74. You are a comedian. You were a member of Monty Python.'
固然,咱們也能夠經過字典的方式直接傳入一個字典來解決代碼過長的問題. 可是,python3.6給咱們提供了更便利的方式.
這種新的方式在PEP498中定義.(原文寫到這裏的時候,做者可能瘋了,balabla說了一長串,冷靜的我並無翻譯這些廢話...) 這種方式也被叫作formatted string literals
.格式化的字符串常亮...ummm...應該是這麼翻譯吧...
這種方式在字符串開頭的時候,以f標識,而後經過佔位符{}+變量名的方式來自動解析對象的__format__方法. 若是想了解的更加詳細,能夠參考python文檔
「使用變量名做爲佔位符」
In [16]: name = 'Eric'
In [17]: age=74
In [18]: f'hello {name}, you are {age}'
Out[18]: 'hello Eric, you are 74'
「這裏甚至可使用大寫的F」
In [19]: F'hello {name}, you are {age}'
Out[19]: 'hello Eric, you are 74'
你覺得這就完了嗎?
不!
事情遠不止想象的那麼簡單...
在花括號裏甚至能夠執行算數表達式
In [20]: f'{2*37}'
Out[20]: '74'
若是數學表達式均可以的話,那麼在裏面執行一個函數應該不算太過度吧...
In [22]: def to_lowercase(input):
...: return input.lower()
...:
In [23]: name = 'ERIC IDLE'
In [24]: f'{to_lowercase(name)} is funny'
Out[24]: 'eric idle is funny'
你覺得這就完了嗎?
不!
事情遠不止想象的那麼簡單...
這玩意兒甚至能夠用於重寫__str__()和__repr__()方法.
class Comedian:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
def __str__(self):
return f"{self.first_name} {self.last_name} is {self.age}."
def __repr__(self):
return f"{self.first_name} {self.last_name} is {self.age}. Surprise!"
>>> new_comedian = Comedian("Eric", "Idle", "74")
>>> f"{new_comedian}"'Eric Idle is 74.'
❝關於__str__()方法和__repr__()方法. 這是對象的兩個內置方法.
❞__str()__
方法用於返回一個便於人類閱讀的字符串. 而__repr__()
方法返回的是一個對象的準確釋義. 這裏暫時不作過多介紹. 若有必要,請關注公衆號吾碼2016(公衆號:wmcoding)併發送str_And_repr
默認狀況下,f-關鍵字會調用對象的__str__()方法. 若是咱們想調用對象的__repr__()方法的話,可使用!r
>>> f"{new_comedian}"
'Eric Idle is 74.'
>>> f"{new_comedian!r}"
'Eric Idle is 74. Surprise!'
更多詳細內容能夠參考這裏
一樣的,咱們可使用多個f-字符串佔位符.
>>> name = "Eric"
>>> profession = "comedian"
>>> affiliation = "Monty Python"
>>> message = (
... f"Hi {name}. "
... f"You are a {profession}. "
... f"You were in {affiliation}."
... )
>>> message
'Hi Eric. You are a comedian. You were in Monty Python.'
可是別忘了,在每個字符串前面都要寫上f
一樣的,在字符串換行的時候,每一行也要寫上f.
>>> message = f"Hi {name}. " \
... f"You are a {profession}. " \
... f"You were in {affiliation}."...
>>> message
'Hi Eric. You are a comedian. You were in Monty Python.'
可是若是咱們使用"""的時候,不須要每一行都寫.
>>> message = f""" ... Hi {name}. ... You are a {profession}. ... You were in {affiliation}. ... """
...
>>> message
'\n Hi Eric.\n You are a comedian.\n You were in Monty Python.\n'
f-字符串的f可能表明的含義是fast,由於f-字符串的速度比佔位符+%的方式和format()函數的方式都要快.由於它是在運行時計算的表達式而不是常量值.(那爲啥就快了呢...不太懂啊...)
❝「F-strings provide a way to embed expressions inside string literals, using a minimal syntax. It should be noted that an f-string is really an expression evaluated at run time, not a constant value.
❞
In Python source code, an f-string is a literal string, prefixed with f, which contains expressions inside braces. The expressions are replaced with their values.」(PEP498)
(官方文檔,咱不敢翻,大意就是f-字符串是一個在運行時參與計算的表達式,而不是像常規字符串那樣是一個常量值)
在運行時,花括號內的表達式在其本身的做用域內求職,單號和字符串的部分拼接到一塊兒,而後返回.
下面咱們來看一個速度的對比.
import timeit
time1 = timeit.timeit("""name = 'Eric'\nage =74\n'%s is %s'%(name,age)""",number=100000)
time2 = timeit.timeit("""name = 'Eric'\nage =74\n'{} is {}'.format(name,age)""",number=100000)
time3 = timeit.timeit("""name = 'Eric'\nage =74\nf'{name} is {age}'""",number=100000)
從結果上看的話,f-字符串的方式速度要比其餘兩種快.
0.030868000000000007 0.03721939999999996 0.0173276
「引號的問題」 在f-字符串中,注意成對的引號使用.
f"{'Eric Idle'}"
f'{"Eric Idle"}'
f"""Eric Idle"""
f'''Eric Idle'''
以上這幾種引號方式都是支持的. 若是說咱們在雙引號中須要再次使用雙引號的時候,就須要進行轉義了. f"The \"comedian\" is {name}, aged {age}."
「字典的注意事項」
在字典使用的時候,仍是要注意逗號的問題.
>>> comedian = {'name': 'Eric Idle', 'age': 74}
>>> f"The comedian is {comedian['name']}, aged {comedian['age']}."
>>> f'The comedian is {comedian['name']}, aged {comedian['age']}.'
好比上面兩條語句,第三句就是有問題的,主要仍是引號引發的歧義.
「花括號」 若是字符串中想使用花括號的話,就要寫兩個花括號來進行轉義. 同理,若是想輸出兩個花括號的話,就要寫四個...
>>> f"{{74}}"'{74}'
>>> f"{{{{74}}}}"
「反斜槓」 反斜槓能夠用於轉義. 可是!!!BUT!!!在f-字符串中,不容許使用反斜槓.
>>> f"{\"Eric Idle\"}" File "<stdin>", line 1 f"{\"Eric Idle\"}" ^SyntaxError: f-string expression part cannot include a backslash
像上面這個的解決辦法就是
>>> name = "Eric Idle"
>>> f"{name}"'Eric Idle'
「行內註釋」 f-字符串表達式中不容許使用#符號.
咱們依舊可使用老的方式進行字符串格式化輸出. 可是經過f-字符串,咱們如今有了一種更便捷,更快,可讀性更高的方式. 根據python教義,Zen of Python:
「there should be one– and preferably only one –obvious way to do it.」 (編程還編出哲理來了...實在不會翻,有一種醍醐灌頂的感受,心裏浮現一個聲音,臥槽!好有道理,彷彿本身昇華了,可是仔細想一想...這句話到底啥意思呢...)
更多的參考資料(我也只是寫在這裏,反正我是沒有閒心看它的...):