Python 3的f-Strings:增強的字串格式語法(指南)
阿新 • • 發佈:2021-02-11
最近也在一個視訊網站的爬蟲,專案已經完成,中間有不少需要總結的經驗。
從Python 3.6開始,f-Strings是格式化字串的一種很棒的新方法。與其他格式化方式相比,它們不僅更具可讀性,更簡潔且不易出錯,而且速度更快!
## Python中的“老式”字串格式化
在Python 3.6之前,你有兩種主要的方式,將Python表示式嵌入到字串文字中進行格式化:%-formatting和`str.format()`。本文將首先介紹如何使用它們以及它們的侷限性。
### 選項#1:%-formatting
這是Python格式化的OG,從一開始就存在於語言中。你可以在[Python文件中](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)閱讀更多內容。請記住,文件不建議使用%格式,其中包含以下注意事項:
> “這裡描述的格式化操作表現出各種古怪問題,導致許多錯誤(例如未能正確顯示元組和字典)。
>
> 使用較新的格式化字串文字或`str.format()`方法有助於避免這些錯誤。這些替代方案還提供了更強大,靈活和可擴充套件的文字格式設定方法。”
#### 如何使用 %-formatting
字串物件具有使用該`%`運算子的內建操作,可用於格式化字串。這是實際的情況:
```python
>>> name = "Eric"
>>> "Hello, %s." % name
'Hello, Eric.'
```
為了插入多個變數,你必須使用這些變數的元組。這是你要執行的操作:
```python
>>> name = "Eric"
>>> age = 74
>>> "Hello, %s. You are %s." % (name, age)
'Hello Eric. You are 74.'
```
#### 為什麼%-formatting不好
上面看到的程式碼示例具有足夠的可讀性。但是,一旦開始使用多個引數和更長的字串,你的程式碼將很快變得不那麼易讀。看起來有些混亂:
```python
>>> first_name = "Eric"
>>> last_name = "Idle"
>>> age = 74
>>> profession = "comedian"
>>> affiliation = "Monty Python"
>>> "Hello, %s %s. You are %s. You are a %s. You were a member of %s." % (first_name, last_name, age, profession, affiliation)
'Hello, Eric Idle. You are 74. You are a comedian. You were a member of Monty Python.'
```
這種格式不是很好,因為它很冗長並且會導致錯誤,例如不能正確顯示元組或字典。
### 選項#2:str.format()
Python 2.6中引入了這種完成工作的新方法。你可以檢視[《 Python字串格式新手指南》以](https://realpython.com/python-formatted-output/)獲取更多資訊。
#### 如何使用str.format()
str.format() 是對 %-formatting 的改進。它使用正常的函式呼叫語法,並且可以通過 __format__() 方法對被轉換為字串的物件進行擴充套件。
使用`str.format()`,替換欄位用花括號標記:
```python
>>> "Hello, {}. You are {}.".format(name, age)
'Hello, Eric. You are 74.'
```
你可以通過引用變數的索引以任何順序引用它們:
```python
>>> "Hello, {1}. You are {0}.".format(age, name)
'Hello, Eric. You are 74.'
```
但是,如果你插入變數名,則會獲得以下額外的好處:能夠傳遞物件,然後在花括號之間引用引數和方法:
```python
>>> person = {'name': 'Eric', 'age': 74}
>>> "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age'])
'Hello, Eric. You are 74.'
```
你也可以使用`**`字典來完成這個巧妙的技巧:
```python
>>> person = {'name': 'Eric', 'age': 74}
>>> "Hello, {name}. You are {age}.".format(**person)
'Hello, Eric. You are 74.'
```
`str.format()` 與%格式相比絕對是一個升級。
#### 為什麼 str.format() 不好
使用`str.format()`程式碼比使用 %-formatting 的程式碼更容易閱讀,但是`str.format()`當你處理多個引數和更長的字串時,程式碼仍然很冗長。看看這個:
```python
>>> 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.'
```
如果你要`.format()`在字典中傳遞變數,則可以將其解壓縮`.format(**some_dict)`並按字串中的鍵引用值,但是必須有一種更好的方法來執行此操作。
## f-Strings表示式:Python中一種增強的格式化字串的新方法
f-Strings 表示式使格式化更容易。他們加入了Python 3.6。你可以在2015年8月由Eric V.Smith撰寫的[PEP 498中](https://www.python.org/dev/peps/pep-0498/)閱讀全部內容。
f-Strings 也稱為“格式化的字串文字”,是一種字串文字,其開頭是 f,後面是大括號,其中包含將被替換為其值的表示式。這些表示式在執行時被評估,然後使用 "__format__" 協議進行格式化。當你想了解更多資訊時,[Python文件](https://docs.python.org/3/reference/lexical_analysis.html#f-strings)是你的朋友。
下面是一些 f-strings 可以讓你的生活更輕鬆的方法。
### 簡單語法
看看這是多麼容易閱讀:
```python
>>> name = "Eric"
>>> age = 74
>>> f"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'
```
使用大寫字母也是有效的`F`:
```python
>>> F"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'
```
### 任意表達
因為 f-strings 在執行時被評估,所以您可以在其中放入任何和所有有效的 Python 表示式。
你可以做一些非常簡單的事情,例如:
```python
>>> f"{2 * 37}"
'74'
```
但是你也可以呼叫函式。這是一個例子:
```python
>>> def to_lowercase(input):
... return input.lower()
>>> name = "Eric Idle"
>>> f"{to_lowercase(name)} is funny."
'eric idle is funny.'
```
你還可以選擇直接呼叫方法:
```python
>>> f"{name.lower()} is funny."
'eric idle is funny.'
```
你甚至可以使用從帶有f-strings的類建立的物件:
```python
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!"
```
你執行以下操作:
```python
>>> new_comedian = Comedian("Eric", "Idle", "74")
>>> f"{new_comedian}"
'Eric Idle is 74.'
```
該`__str__()`和`__repr__()`方法處理物件是如何呈現為字串,所以你需要確保你包括你的類定義這些方法的至少一個。如果你必須選擇一個,請繼續使用,`__repr__()`因為它可以代替使用`__str__()`。
返回的`__str__()`字串是物件的非正式字串表示形式。返回的字串`__repr__()`是正式表示形式,應明確。呼叫`str()`和`repr()`比直接使用`__str__()`和更可取`__repr__()`。
預設情況下,f字串將使用`__str__()`,但是如果你加入轉換標誌 !r,你可以確保它們使用`__repr__()`:
```python
>>> f"{new_comedian}"
'Eric Idle is 74.'
>>> f"{new_comedian!r}"
'Eric Idle is 74. Surprise!'
```
如果你想閱讀一些導致 f-Strings 支援完整Python表示式的對話,則可以在[此處進行](https://mail.python.org/pipermail/python-ideas/2015-July/034726.html)。
### 多行f-Strings
你可以使用多行字串:
```python
>>> 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。以下程式碼不起作用:
```python
>>> message = (
... f"Hi {name}. "
... "You are a {profession}. "
... "You were in {affiliation}."
... )
>>> message
'Hi Eric. You are a {profession}. You were in {affiliation}.'
```
如果你沒有`f`在每行的前面都放一個,那麼你將只有規則的,古老的,花園風格的琴絃,而不是閃亮的,新穎的,奇特的f琴絃。
如果你想將字串分佈在多行中,則還可以選擇使用-轉義字元 `\`:
```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.'
```
但是,如果使用以下方法,將會發生以下情況`"""`:
```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'
```
閱讀[PEP 8中的](https://pep8.org/)縮排準則。
### 速度
f-Strings 比 %-formatting 和 str.format() 都要快。如你所見,f-Strings 是在執行時求值的表示式,而不是常量值。以下摘自文件:
> “f-Strings 提供了一種使用最小語法在字串文字中嵌入表示式的方法。應當注意,f-Strings 實際上是在執行時評估的表示式,而不是常數。在Python原始碼中,f-Strings 是文字字串,字首為`f`,其中花括號內包含表示式。這些表示式將替換為其值。” ([來源](https://www.python.org/dev/peps/pep-0498/#abstract))
在執行時,大括號內的表示式在其自己的範圍內求值,然後與 f-Strings 的字串文字部分放在一起。然後返回結果字串。這就是全部。
這是速度比較:
```python
>>> import timeit
>>> timeit.timeit("""name = "Eric"
... age = 74
... '%s is %s.' % (name, age)""", number = 10000)
0.003324444866599663
```
```python
>>> timeit.timeit("""name = "Eric"
... age = 74
... '{} is {}.'.format(name, age)""", number = 10000)
0.004242089427570761
```
```python
>>> timeit.timeit("""name = "Eric"
... age = 74
... f'{name} is {age}.'""", number = 10000)
0.0024820892040722242
```
如你所見,f-Strings 最快。
但是,情況並非總是如此。首次實施時,它們存在一些[速度問題](https://stackoverflow.com/questions/37365311/why-are-literal-formatted-strings-so-slow-in-python-3-6-alpha-now-fixed-in-3-6),需要使其速度比更快`str.format()`。引入了特殊的[`BUILD_STRING`操作碼](https://bugs.python.org/issue27078)。
## Python f-Strings:細節
既然你已經瞭解了為什麼 f-Strings 很棒,我相信你一定要開始使用 f-Strings 。當你冒險進入這個勇敢的新世界時,請牢記以下一些細節。
### 引號
你可以在表示式內使用各種型別的引號。只要確保你沒有在表示式中使用與 f-Strings 相同的引號即可。
該程式碼將起作用:
```python
>>> f"{'Eric Idle'}"
'Eric Idle'
```
該程式碼也將起作用:
```python
>>> f'{"Eric Idle"}'
'Eric Idle'
```
你還可以使用三引號:
```python
>>> f"""Eric Idle"""
'Eric Idle'
```
```python
>>> f'''Eric Idle'''
'Eric Idle'
```
如果發現需要在字串的內部和外部使用相同型別的引號,則可以使用 `\` 命令進行轉義:
```python
>>> f"The \"comedian\" is {name}, aged {age}."
'The "comedian" is Eric Idle, aged 74.'
```
### 字典
說到引號,使用字典時要當心。如果要對字典的鍵使用單引號,請記住確保對包含鍵的 f-Strings 使用雙引號。
這將起作用:
```python
>>> comedian = {'name': 'Eric Idle', 'age': 74}
>>> f"The comedian is {comedian['name']}, aged {comedian['age']}."
The comedian is Eric Idle, aged 74.
```
但這是一個語法錯誤的情況:
```python
>>> comedian = {'name': 'Eric Idle', 'age': 74}
>>> f'The comedian is {comedian['name']}, aged {comedian['age']}.'