---
# System prepended metadata

title: String Format in Python
tags: [' percent_string', python, ' string_format', ' fstring']

---

---
title: String Format in Python
description: Introduction to 4 ways of formatting string in Python.
tags: python, fstring, percent_string, string_format
GA: UA-206161787-1
lang: zh
---

###### tags: `yt` `python`

# String Format in Python

## 什麼是String Format?

舉例而言，我們在看YouTube時，在影片的下方都會顯示影片的標題以及影片發布的日期，而這些文字在每部影片中的格式都是一樣的，像是`xx小時前`之類的，有改動的地方只有`xx`，剩下的部分是不變的。這種生成固定格式字串的過程，我們就稱之為String Format。


## 4種方法

下面我們透過同一個例子來示範這四種常見的的方法。

[完整程式碼](https://colab.research.google.com/drive/1pZNhX48pTOxv1B9_crGjkO6bzhf7ZQJr?usp=sharing)

| #   | Method       | Support      |
| --- | ------------ | ------------ |
| 1   | `+` 串接     | all versions |
| 2   | %-string     | all versions |
| 3   | str.format() | >= python2.6 |
| 4   | f-string     | >= python3.6 |


---

> 我們的目標是要印出標題與發布的日期。

Setup:
```python=
from datetime import datetime

title = "Python EP 0"
timestamp = datetime.now()
```

Output:
```
Title: Python EP 0, Posted on 8/23
```

### 1. `+` 串接

第一種方法是透過`+`直接把各個字串組合在一起。

```python=
print("Title: " + title + ", Posted on " + str(timestamp.month) + "/" + str(timestamp.day))
```

這種方法很直觀，但要注意，串接在一起的變數都必須是字串，像這邊我們就得把`Timestamp`中的月份與日期透過內建的`str`函式，把他們從`int`轉成`str`，這樣他們才可以正確地被串接在一起。

### 2. %-string

第二種方法是透過`%-string`，早期的Python就有支援類似C語言的`%-string`語法。使用的方法是，在我們想要替換的位置打上`%s`來標記，隨後透過`%`的Operator傳入一個含有目標字串的`Tuple`，注意，傳入的`Tuple` 必須包含所有要被置換的變數，個數不能多也不能少。像這邊我們有三個`%s`的placeholder，那就得傳入三個變數，分別是`title`和`timestamp`的月份及日期。

```python=
print("Title: %s, Posted on %s/%s" % (title, timestamp.month, timestamp.day))
```

### 3. str.format()

第三種方法是呼叫string中foramt的函式，這種方法在Python2.6之後開始支援，使用起來與`%-string`相似，他用大括號（`{}`）來標記要取代的位置，再透過呼叫`format()`的函式，傳入要取代的實際內容。此外，它提供了許多進階的功能，像是能為傳入的變數命名，並且在直接在字串中存取物件的屬性（Attribute）。像這邊，我們就標記並命名了三個要取代的地方，直接在大括號中存取`timestamp`的月份與日期。

```python=
print("Title: {t}, Posted on {ts.month}/{ts.day}".format(t=title, ts=timestamp))
```

### 4. f-string

最後一種方法稱為`f-string`，這在Python3.6之後才開始支援。使用的方法是，在定義字串的引號前，加上小寫或是大寫的`f`，接著與第三種呼叫`str.format()`相似，也是用大括號表示要取代的位置，但是他可以直接存取變數的名稱，而不需要再把對應的變數傳入。像這邊，我們可以在`f-string`中存取要顯示的變數`{title}`以及`{timestamp}`，在存取的同時，又可以利用冒號（`:%-m/%d`）來格式化顯示的日期。

```python=
print(f"Title: {title}, Posted on {timestamp:%-m/%d}")
```

## 我應該要用哪個？

首選是`f-string`，目前大部分的平台都已支援Python3.6+的版本了，`f-string`繼承了前面幾種方法的優點，兼顧程式碼的可讀性，即使是較長的格式化字串，讀者也能一眼就能看出這個位置要替換的目標是哪個變數。更重要的是，`f-string`也是這四種方法裡面，建構字串的速度最快的。

這邊我們分別對四個方法跑一百萬次，看看彼此之間速度的差異。

```python=
import timeit

ITERATIONS = 1_000_000

name = "John Doe"
age = 30

# +
plus_string_elapsed = timeit.timeit(lambda: name + " is " + str(age) + ".", number=ITERATIONS)

# Percent string
percent_string_elapsed = timeit.timeit(lambda: "%s is %s." % (name, age), number=ITERATIONS)

# str.format()
str_format_elapsed = timeit.timeit(lambda: "{} is {}.".format(name, age), number=ITERATIONS)

# f-string
f_string_elapsed = timeit.timeit(lambda: "{name} is {age}.", number=ITERATIONS)

result = (
    f"plus string: {plus_string_elapsed:.3} s\n"
    f"percent string: {percent_string_elapsed:.3} s\n"
    f"str_format: {str_format_elapsed:.3} s\n"
    f"f-string: {f_string_elapsed:.3} s"
)
print(result)
```

結果

```
plus string:    0.449 s
percent string: 0.373 s
str_format:     0.427 s
f-string:       0.0897 s
```

## 後記

對於每個方法更詳細的使用說明以及其中的雷，可以參考我在Colab上的[互動式範例](https://colab.research.google.com/drive/1pZNhX48pTOxv1B9_crGjkO6bzhf7ZQJr?usp=sharing)。