Python 字符串插值:初學者指南

假設你想輸出一個人的名字和職業。你可以編寫一個簡單的程式如下。

# 定義變數 name = 'Mark' profession = 'Astronaut' age = 7 # 輸出資訊 output_string = ('My name is ' + name + ', I am ' + str(age) + ' years old ' + 'and my profession is ' + profession + '.') print(output_string)
My name is Mark, I am 7 years old and my profession is Astronaut.

這種方法缺乏簡潔性和可讀性。幸運的是,字符串插值提供了一個更好的解決方案。它允許將變數、表達式或函數輸出直接插入字符串中,使字符串操作動態化,消除了手動串聯的需求。

使用字符串插值方法,我們可以將代碼重寫如下。

# 定義變數 name = 'Mark' profession = 'Astronaut' age = 7 # 輸出資訊 output_string = f'My name is {name}, I am {age} years old and my profession is {profession}.' print(output_string)
My name is Mark, I am 7 years old and my profession is Astronaut.

具有字符串插值的版本允許在字符串內直接嵌入表達式,而無需使用混亂的串聯。正如你所看到的,這是一種更乾淨的方法。

Python中的基本字符串插值

Python中有幾種不同的字符串插值技術可用。最常推薦的方法是格式化字符串字面量,也被稱為f-strings,這自Python 3.6版本開始可用。

另一種在Python 3.6之前的代碼中常見的方法是.format()方法。雖然這種方法比f-strings更冗長,但偶爾有其優勢(詳情如下)。

最後,您可能會在舊代碼中遇到%風格的格式化。

使用f-strings(Python 3.6+)

f-strings
(格式化字符串字面值)是在Python中格式化字符串的一種強大而簡潔的方式。它們在Python 3.6中引入,提供了一種可讀性高且有效率的方式,可以直接將變量、表達式和函數調用插入字符串中。

一個 f-string 基本語法的簡單示例如下。

name = 'Mark' output_string = f'My name is {name}.' print(output_string)
My name is Mark.

在這段程式碼中,output_string 變數被指定為一個 f-string。開頭引號前的 f 前綴表示該字串支援嵌入式表達式。變數 name 被評估,其值被插入到字串中,產生輸出:"My name is Mark."

不僅可以插入變數值,還可以插入計算或表達式到 f-string 中。考慮以下示例。

import math a = 3.0 b = 4.0 # 使用字串插值來計算公式 print(f'The hypotenuse of a triangle with base {a} and side {b} is {math.sqrt(a ** 2 + b ** 2)}.')
The hypotenuse of a triangle with base 3.0 and side 4.0 is 5.0.

表达式math.sqrt(a ** 2 + b ** 2)在字符串内直接评估,无需在插入字符串之前单独计算该值。

使用.format()方法

与f-strings类似,.format()方法允许将变量和表达式插入字符串中。 .format()方法的基本语法如下。

name = 'Mark' output_string = 'My name is {}.'.format(name) print(output_string)
My name is Mark.

大括號{}作為佔位符,表示變數的值將被插入到該位置的字符串中。插入到佔位符中的特定變數值由提供給.format()方法的參數確定。

位置參數

如果需要多個變數的多個佔位符,會發生什麼情況?請考慮以下代碼。

name = 'Mark' age = 7 # 將按照參數的順序填充佔位符 output_string = 'My name is {} and I am {} years old.'.format(name, age) print(output_string)
My name is Mark and I am 7 years old.

在這個例子中,需要兩個變量nameage。因此,字符串包含兩個佔位符,變量按照它們在.format()方法中出現的順序插入。這些參數稱為*位置*參數,因為它們在字符串中的位置取決於它們在方法參數列表中的位置。

索引和命名的佔位符

作為佔位符概念的一種變化,請考慮這個例子。

name = 'Mark' age = 7 # 打印兩次年齡 output_string = 'My name is {} and I am {} years old. My twin brother is also {} years old.'.format(name, age, age) print(output_string)
My name is Mark and I am 7 years old. My twin brother is also 7 years old.

這裡,我們重複使用了變數age兩次。像這樣多次包含同一變數會讓代碼變得笨重並降低可讀性。有沒有一種方法可以在使用.format()方法格式化字符串時重複使用變數而不必重複它?是的,有,可以使用所謂的*索引占位符*

name = 'Mark' age = 7 # 使用索引占位符 output_string = 'My name is {0} and I am {1} years old. My twin brother is also {1} years old.'.format(name, age) print(output_string)
My name is Mark and I am 7 years old. My twin brother is also 7 years old.

在這個例子中,我們明確定義了大括號內變數的順序,遵循Python的從零開始的索引。此外,我們重複使用了索引為1的變數,而不是重複它。

作為位置索引的替代,您也可以使用命名參數,其中每個參數都被賦予一個名稱。

print('My name is {name} and I am {age} years old.'.format(name='Mark', age=7))
My name is Mark and I am 7 years old.

被命名的參數在指定其名稱的大括號內進行評估。因此,{name} 佔位符被替換為 "Mark",而 {age} 佔位符則被替換為 30

使用 % 運算符。

字串插值的最後一種方法是 % 運算子。它的功能類似於 printf() 命令在C語言中的用法。儘管它被廢棄並且強烈不建議使用,而是建議使用f-strings或 .format() 方法。這裡提到它是因為你可能會在舊代碼中遇到它。

運算子的基本格式為:“格式字串”%值。格式字串包含佔位符,例如%s代表字符串,它將被值取代。例如,以下範例將打印出”Hello, Mark。”

'Hello %s' % 'Mark'
'Hello Mark'

其他常見的格式化符號如下表所示。

格式符號

意義

範例

%s

字符串

“Hello %s”%”Alice” → “Hello Alice”

%d

整數(十進制)

“年齡: %d” % 25 → “年齡: 25”

%f

浮點數 (預設 6 位小數)

“圓周率: %f” % 3.14159 → “圓周率: 3.141590”

%.nf

浮點數 (n 位小數)

“%.2f” % 3.14159 → “3.14”

%x

十六進制 (小寫)

“%x” % 255 → “ff”

%X

十六進制 (大寫)

“%X” % 255 → “FF”

%o

八進制

“%o” % 255 → “377”

The % 運算子有許多限制。首先,它比f-strings不太易讀。考慮以下代碼。

name = "Alice" age = 30 height = 5.6 # % 運算子很難掃描 message = "My name is %s, I am %d years old, and my height is %.1f feet." % (name, age, height) print(message)
My name is Alice, I am 30 years old, and my height is 5.6 feet.

這段代碼一目瞭然嗎?可能不是。在佔位符和填充空白的變數之間來回進行視覺解析。很容易在來回掃描中感到困惑(或頭暈)。

現在,考慮使用f-strings的等效代碼。

# 這樣更清晰 message = f"My name is {name}, I am {age} years old, and my height is {height:.1f} feet." print(message)
My name is Alice, I am 30 years old, and my height is 5.6 feet.

無需掃描,也不需要模糊的格式化字符串。代碼乾淨,易於理解和編寫。您可以通過DataCamp的Python Programming技能軌道學習編寫清晰、優化代碼的其他技巧。ython Programming skill track

高級Python字符串插值技術

現在我們已經了解了Python字符串插值的基礎,讓我們看一些更高級的用法。

Python多行字符串插值

通過使用帶有三引號的f標識符(單引號或雙引號),f-strings也可以用於多行內容。文本可以跨多行編寫,並且將按照格式準確顯示在輸出中。

name = 'Mark' profession = 'Astronaut' age = 7 # 這是多行字符串的示例 bio = f""" Name: {name} Profession: {profession} Age: {age} """ print(bio)
Name: Mark Profession: Astronaut Age: 7

使用.format()方法也可以創建多行字符串。

name = 'Mark' profession = 'Astronaut' age = 7 # 這是一個使用.format()的多行字符串 bio = """ Name: {} Profession: {} Age: {} """.format(name, profession, age) print(bio)
Name: Mark Profession: Astronaut Age: 7

多行字符串插值的用例

為什麼要使用多行字符串插值?有許多多行字符串插值的用例。以下是一些用例:

  • 生成多行電子郵件或消息
  • 記錄和調試
  • 動態生成SQL查詢

生成多行電子郵件或消息

假設你要向許多受邀參加技術大會的人發送一封表格信。

name = "Alice" event = "Annual Tech Conference" date = "March 15, 2025" email = """Dear {name}, We are pleased to invite you to the {event} taking place on {date}. We hope you can join us for an exciting experience. Best regards, The Event Team""".format(name=name, event=event, date=date) print(email)
Dear Alice, We are pleased to invite you to the Annual Tech Conference taking place on March 15, 2025. We hope you can join us for an exciting experience. Best regards, The Event Team

使用f-strings,創建表格信簡單高效。要更改姓名、活動或日期,只需在變量中更改它們,字符串就會自動更改。

記錄和調試

多行字符串對於打印日誌中的錯誤消息很有用。

error_code = 404 url = '/missing-page' timestamp = '2025-02-05 12:30:00' error_message = 'The requested page could not be found.' log_message = f"""[ERROR {error_code}] Time: {timestamp} URL: {url} {error_message}""" print(log_message)
[ERROR 404] Time: 2025-02-05 12:30:00 URL: /missing-page The requested page could not be found.

這種方法保持日誌消息結構化,使調試更容易,具有格式良好的日誌。

動態生成SQL查詢

可以使用多行字符串動態構建SQL查詢。

table = 'users' column = 'email' value = '[email protected]' query = f"""SELECT * FROM {table} WHERE {column} = '{value}';""" print(query)
SELECT * FROM users WHERE email = '[email protected]';

這種方法使得 SQL 查詢更易讀且保持縮排。此外,它消除了需要使用+進行字符串連接的必要。

其他使用情況包括:

  • 編寫格式化合同
  • 創建 Markdown 或 $\LaTeX$ 文件
  • 多行 HTML/XML 模板
  • 生成API回應或類似JSON的文字

多行字串插值的優點

從這裡我們可以看到,多行字串插值有幾個優點。

  • 字串插值保留格式而無需使用跳脫字元\n
  • 與單行格式相比,字串插值提高了可讀性。
  • 在處理結構化文字時(例如日誌、查詢、報告),字串插值減少了混亂。
  • 字符串插值允許動態生成文本,而不會破壞縮排。

格式化數字和特殊值

要使用 f-string 控制顯示的小數位數,請使用以下語法:f'{value:.nf}',其中value是浮點數,n是小數位數,f(在.後面的那個)代表浮點數格式化。

舉例來說,以下程式碼輸出$\pi$至不同的小數位。

pi = 3.1415926535 print(f'Pi rounded to 2 decimal places: {pi:.2f}') print(f'Pi rounded to 4 decimal places: {pi:.4f}') print(f'Pi rounded to 0 decimal places: {pi:.0f}')
Pi rounded to 2 decimal places: 3.14 Pi rounded to 4 decimal places: 3.1416 Pi rounded to 0 decimal places: 3

使用.format()方法進行格式化是類似的。

print('Pi rounded to 2 decimal places: {:.2f}'.format(pi)) print('Pi rounded to 4 decimal places: {:.4f}'.format(pi)) print('Pi rounded to 0 decimal places: {:.0f}'.format(pi))
Pi rounded to 2 decimal places: 3.14 Pi rounded to 4 decimal places: 3.1416 Pi rounded to 0 decimal places: 3

您可以使用f-string,通過:.nf語法結合%,其中n是小數位數。

score = 0.875 print(f"Success rate: {score:.2%}")
Success rate: 87.50%

您可以使用 f-string 來格式化貨幣,方法是使用 :, 來加入千位分隔符,以及 .nf 來控制小數位數。您也可以直接在字串中包含貨幣符號,如 $、€ 或 £。

amount = 98765.4321 print(f"USD: ${amount:,.2f}") print(f"EUR: €{amount:,.2f}") print(f"GBP: £{amount:,.2f}")
USD: $98,765.43 EUR: €98,765.43 GBP: £98,765.43

使用字典和列表的 f-strings

在 Python 中使用 f-strings 與字典時,可以在大括號內使用方括號表示法(dict[‘key’])來訪問字典值,或者通過 ** 將字典展開。

person = { 'name': 'Alice', 'age': 30, 'city': 'New York' } print(f"My name is {person['name']}, I am {person['age']} years old, and I live in {person['city']}.")
My name is Alice, I am 30 years old, and I live in New York.

您可以將字典展開到 f-string 中,而不是手動訪問每個鍵。

person = { 'name': 'Alice', 'age': 30, } print(f'My name is {name} and I am {age} years old.'.format(**person))
My name is Alice and I am 7 years old.

為了避免缺少鍵而產生錯誤,請使用 get() 進行字典訪問。

person = {"name": "Alice"} # 錯誤:缺少鍵 'city' print(f"City: {person['city']}")
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[87], line 4 1 person = {"name": "Alice"} 3 # 錯誤:缺少鍵 'city' ----> 4 print(f"City: {person['city']}") KeyError: 'city'
print(f"City: {person.get('city', 'Not specified')}")
City: Not specified

字符串插值方法的優缺點

如我們所看到的,f-strings和.format()方法都是用於字串插值的有用方法。讓我們來比較一下每種方法的優缺點。Feature

f-strings

.format()

% formatting

Readability

🟢 最佳

🟡 可接受

🔴 較困難

Performance

🟢 最快

🟡 較慢

🔴 最慢

Supports Expressions

🟢 是

🟡 間接

🔴 否

多行支持

🟢 是

🟢 是

🔴 否

使用便捷性

🟢 最方便

🟡 中等

🔴 困難

調試(= 運算子)

🟢 是(Python 3.8+)

🔴 否

🔴 否

什麼時候應該使用 .format() 而不是 f-strings?

優勢

為什麼使用 .format()

遺留的Python支援

適用於Python 2.7+

彈性排序

允許輕鬆重新排序佔位符

動態格式化

當格式指定器是動態時運作

更好地處理{}大括號

避免額外手動轉義

與字典協作良好

更容易使用字典鍵

常見問題和最佳實踐

在下面,您可以找到一些用於Python字符串插值的疑難排解方法和頂級提示。

避免使用大括號時的語法錯誤

使用涉及花括号的字符串插值时,可能会出现许多语法错误。

  • 确保每个 { 都有对应的 }
print('Hello, my name is {name!'}
Cell In[96], line 1 print('Hello, my name is {name!'} ^ SyntaxError: closing parenthesis '}' does not match opening parenthesis '('

幸运的是,这种错误很明显,修复起来也很容易。

  • 使用{{和}}来显示文字 {}

如果要在插值字符串中打印花括号会发生什么?花括号内的任何内容都将(尝试)被评估。

print(f'Set notation: {a, b, c}')
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[101], line 1 ----> 1 print(f'Set notation: {a, b, c}') NameError: name 'c' is not defined

Python 将花括号内的 a、b、c 解释为元组,尝试查找与 a 关联的值。由于不存在这样的变量,它会引发 KeyError。解决方法是使用双花括号 {{}}

print("Set notation: {{a, b, c}}")

集合表示:{{a, b, c}}

性能比较:f-strings vs .format()

让我们比较一下 f-strings 和 .format() 的性能

import timeit name = "Alice" age = 30 pi = 3.1415926535 # 測量 f-string 的效能 f_string_time = timeit.timeit('f"My name is {name} and I am {age} years old."', globals=globals(), number=1000000) # 測量 .format() 的效能 format_time = timeit.timeit('"My name is {} and I am {} years old.".format(name, age)', globals=globals(), number=1000000) # 測量帶有表達式的 f-string 效能 f_string_expr_time = timeit.timeit('f"Pi rounded to 2 decimal places: {pi:.2f}"', globals=globals(), number=1000000) # 測量帶有表達式的 .format() 效能 format_expr_time = timeit.timeit('"Pi rounded to 2 decimal places: {:.2f}".format(pi)', globals=globals(), number=1000000) # 列印結果 print(f"f-string (simple): {f_string_time:.6f} seconds") print(f".format() (simple): {format_time:.6f} seconds") print(f"f-string (with expression): {f_string_expr_time:.6f} seconds") print(f".format() (with expression): {format_expr_time:.6f} seconds")
f-string (simple): 0.080447 seconds .format() (simple): 0.129860 seconds f-string (with expression): 0.123171 seconds .format() (with expression): 0.146242 seconds

從效率的角度來看,人們應該偏好使用 f-strings 而不是 .format()

潔淨且可讀性的字串插值最佳實踐

為確保您的字串格式清晰、高效且易於維護,使用插值字串時請遵循以下最佳實踐。

  • 偏好使用 f-strings 以提升可讀性(Python 3.6+)
# 建議 name = "Alice" age = 30 print(f"My name is {name} and I am {age} years old.") # 不建議(可讀性較差) print("My name is {} and I am {} years old.".format(name, age)) # 避免使用 % 格式化(已過時) print("My name is %s and I am %d years old." % (name, age))
My name is Alice and I am 30 years old. My name is Alice and I am 30 years old. My name is Alice and I am 30 years old.
  • 使用具名佔位符以提高清晰度
# 命名占位符(易读) user = {"name": "Alice", "age": 30} print(f"My name is {user['name']} and I am {user['age']} years old.") # 在 .format() 中使用索引(不易读) print("My name is {0} and I am {1} years old.".format("Alice", 30))
My name is Alice and I am 30 years old. My name is Alice and I am 30 years old.
  • 保持多行字符串易读。
name = "Alice" age = 30 message = f"""Hello, {name}! We are happy to invite you to our event. At {age} years old, you are eligible for the VIP pass. Best regards, Event Team """ print(message)
Hello, Alice! We are happy to invite you to our event. At 30 years old, you are eligible for the VIP pass. Best regards, Event Team
  • 在日志记录中使用 f-strings 进行更好的调试

Python 3.8 及更高版本支持在 f-strings 中进行调试。

value = 42 # Output: value = 42 print(f"{value = }")
value = 42

结论

字符串插值是 Python 中的一个强大功能,使字符串格式化更清晰、更易读、更高效。在可用的方法中,f-strings 是最现代化和推荐的方法,相比于旧方法如 .format()% 格式化,提供更好的性能、清晰度和灵活性。

通過遵循最佳實踐,如使用具名佔位符、控制小數精度、對齊文本以提高可讀性,並優雅地處理缺失的字典鍵,您可以在Python中撰寫乾淨、專業和易於維護的字符串格式化。

無論您正在生成格式化報告、多行消息還是結構化數據輸出,f-strings提供了一種簡單而強大的集成變量和表達式的方式。採用f-strings不僅可以提高代碼質量,還可以增強其效率。

有關Python字符串插值的更多信息,請查看DataCamp的資源:

Source:
https://www.datacamp.com/tutorial/python-string-interpolation