トラック
/
Python
Python
/
シラバス
/
文字列の書式設定
文字

文字列の書式設定 の Python

1個の演習

文字列の書式設定について

Pythonの文字列フォーマット

文字列フォーマットとは、値を文字列に変換し、それを文字列テンプレートに挿入する作業のことです。 Pythonの禅は、「Pythonで何かを行うには_明らかな_方法が1つあるべきだ」と説いています。 しかし、文字列フォーマットのこととなると、話は少し…禅から遠ざかります。

Pythonには文字列フォーマットを行う主な方法が4つもあると知ると、驚くかもしれません。しかも、それぞれ異なる場面で使います。 これは一部にはPythonの長い歴史によるもので、一部には国際化や入力のサニタイズといった事情によるものです。 ここでは、文字列フォーマットの道具箱に最も新しく加わったものから始めて、「旧スタイル」すなわち「printf()スタイル」の文字列フォーマットへと、順を追ってさかのぼっていきます。

リテラル文字列補間: f-string

Python 3.6で導入されたf-string(「formatted strings」の略)またはリテラル文字列補間は、引用符の前にf(またはF)を付けて(例: f'{object}')、式や文字列を手早く効率よく評価し(そしてフォーマットし)てstr型にする方法です。

f-stringは、1行の文字列('または")や複数行の文字列('''または""")など、あらゆる囲み方の文字列型で使えます。 {}の中に置いた変数、式、その他の型は、まず評価され、次にstrに変換され、最後に波括弧の外側にあるstrと連結されます。

次の例では、2つの変数の値(strが1つとfloatが1つ)を文に挿入します。

>>> name = 'eighth'
>>> value = 1/8

# The f-string, using the two values.
# The .2f format code truncates, so the value displays as 0.12.
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.'

評価できる式は、ほぼ何でもあります。 評価できる可能性の(幅広い)一部を挙げると、str、数値、変数、算術式、条件式、組み込み型、スライス、関数、ラムダ、内包表記、そして__str__や__repr__メソッドが定義されたあらゆるオブジェクトです。

単純なものから複雑なものへと見ていきましょう。

変数を挿入する。f-stringの最も単純な使い方は、変数をそのまま文字列の中に置くことです。

# Assigning a variable.
>>> name = "World"

# Inserting that variable.
>>> f'Hello, {name}!'
'Hello, World!'

{}の中の式。波括弧の中では、有効なPythonの式なら何でも評価できます。 シングルクォートで囲んだf-stringの中でダブルクォートを使う(またはその逆)と、エスケープシーケンスが不要になる点に注目してください。

# A dictionary of key:value pairs.
>>> waves = {'water': 1, 'light': 3, 'sound': 5}

# Inserting the whole dict.
>>> f'Wave ranks: {waves}'
"Wave ranks: {'water': 1, 'light': 3, 'sound': 5}"

# An expression can be evaluated inline:
>>> f"Tenfold the value of 'light' is {waves['light'] * 10}."
"Tenfold the value of 'light' is 30."

# A method call can also be evaluated inline:
>>> f'{"hello world!".title()} is a classic greeting.'
'Hello World! is a classic greeting.'

# An f-string can be nested inside another f-string:
>>> f"{f'hello world!'.title()} is a classic greeting."
'Hello World! is a classic greeting.'

出力のフォーマット。フォーマット仕様ミニ言語を使うと、配置、数値の精度などを細かく制御できます。 フォーマット仕様は値のあとに:で区切って書きます。

# Right-align a value to ten characters, and round it to 3 decimal places.
>>> value = 1 / 7
>>> f'One seventh is {value:10.3f}.'
'One seventh is      0.143.'

# A format specification can be set using variables as well.
>>> padding = 10
>>> precision = 3
>>> f'One seventh is {value:{padding}.{precision}f}.'
'One seventh is      0.143.'

すべてを組み合わせる。変数、式、関数呼び出し、出力のフォーマット:

>>> precision = 3
>>> f"{30e8 * 111_000:6.{precision}e}"
'3.330e+14'

>>> verb = 'meet'
>>> the_end = ['end', 'of', 'transmission']
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {30e8 * 111_000:6.{precision}e} light-years."{the_end}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."[\'end\', \'of\', \'transmission\']'

# Did you notice the escaped single-quotes in the previous example?
# Using double quotes instead of single quotes for the f-string means the list's single-quoted strings print cleanly.
>>> f"Have a nice day. {the_end}"
"Have a nice day. ['end', 'of', 'transmission']"

気をつけておきたい主な制限が2つあります。 f-stringの式は空にできません。 さらに、Python 3.12より前ではコメントを含めることができませんでした。

>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed

>>> word = 'word'
>>> f"""A comment in a triple quoted f-string: {
    word # I chose a nice variable
}"""
'A comment in a triple quoted f-string: word'
Caution

国際化(I18N)と地域化(L10N)のためのGNU gettext APIと文字列補間を一緒に使うことはできません。そのため、「文字列のラップ」を伴う翻訳の場面では、f-stringではなく、後述するstring.Templateクラスまたはstr.format()メソッドを使うことをおすすめします。

また、f-stringの括弧{}の中で式を使うのは、eval()やexec()を使うのに似ている点も覚えておいてください。あまり安全ではないので、ユーザー入力に対しては決して使わないでください。

str.format()メソッド

str.format()メソッドは、文字列内のプレースホルダーを、関数の引数として渡された値で置き換えます。 プレースホルダーは、名前({price})、番号({0}、つまりインデックス)、あるいは空の(_位置指定_の)プレースホルダー{}で指定します。

たとえば:

# A named placeholder and a positional placeholder.
>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
'My text: named placeholder and 12.'

f-stringと同様、Pythonのstr.format()はさまざまなミニ言語フォーマット指定子をサポートしています。これらを使うと、テキストの配置、小数の切り捨てなどができます。

フォーマット指定子の完全なパターンは{[<name>][!<conversion>][:<format_specifier>]}です:

  • <name>は名前付きプレースホルダー、番号、または空にできます。
  • !<conversion>は省略可能で、次の3つの変換のいずれかにします: str()の!s、repr()の!r、ascii()の!aです。 既定ではstr()が使われます。
  • :<format_specifier>は省略可能で、値の表示方法を制御します。 指定できるオプションの詳細はこちらにあります。

発音区別符号の付いた文字に対する変換の例を見てみましょう:

# Fills in the object at index zero, converted to a string.
>>> 'An e with an umlaut: {0!s}'.format('ë')
'An e with an umlaut: ë'


# Fills in the object at index zero, converted to a repr.
>>> 'An e with an umlaut (object representation): {0!r}'.format('ë')
"An e with an umlaut (object representation): 'ë'"


# Fills in the object at index zero, converted to ASCII.
>>> 'An e with an umlaut converted into ASCII: {0!a}'.format('ë')
"An e with an umlaut converted into ASCII: '\xeb'"


# Fills in the object in the first position,
# then fills in the object in the second position formatted as a repr.
>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."

よく使うフォーマット指定子の例:

# Integer and binary/hex representations of the same number.
>>> my_num = 42
>>> f"{my_num} in binary is {my_num:b}. In hex, it is {my_num:x}"
"42 in binary is 101010. In hex, it is 2a"

# Alignment: left (<), right (>), and center (^) using up to ten characters total.
>>> f"[{"left":<10}] [{"right":>10}] [{"center":^10}]"
"[left      ] [     right] [  center  ]"

# Float precision and scientific notation (up to three decimal places).
>>> pi = 3.141592653589793
>>> f"Fixed: {pi:.3}  Scientific: {pi:.3e}"
"Fixed: 3.142  Scientific: 3.142e+00"

# Thousands separator and percentage.
>>> balance = 1000
>>> rate = 0.0225
>>> f"Balance: ${balance:,.0f}  Interest rate: {rate:.1%}"
"Balance: $1,000  Interest rate: 2.2%"

# Putting it all together:
>>> items = [("Widget", 1250, 9.991), ("Gadget", 37, 24.503), ("Doohickey", 4, 149.002)]
>>> header = f"{"Item":<12} {"Qty":>6} {"Price":>9}"
>>> print(header)
Item            Qty     Price
>>> for name, qty, price in items:
...     print(f"{name:<12} {qty:>6} {price:>9.2f}")
Widget         1250      9.99
Gadget           37     24.50
Doohickey         4    149.00

さらに多くの例がこちらのドキュメントの末尾に載っています。

%フォーマット、別名printf()スタイルフォーマット

フォーマットに%演算子を使う方法は、Pythonで最も古い文字列フォーマットのやり方です。 C言語に由来し、位置引数を使ってstrを組み立てられます。

この方法はf-stringとstr.format()の両方に取って代わられており、そのため%フォーマットは_「旧スタイル」と呼ばれています。 Python 2やレガシーなコードでは今でも見かけます。 この方法はPython 3.xでも動きますが、%フォーマットはふだん避けられます。間違いを招きやすく、効率が悪く、使えるオプションも少なく、プレースホルダーと引数が合わないと例外が発生するからです。 %演算子の使い方はprintf()に似ているので、printfフォーマット_と呼ばれることもあります。

# Assigning a variable.
>>> name = "Anna-conda"

# Building a string using %.
>>> "The snake's name is %s." % name
"The snake's name is Anna-conda."

上の例では、%演算子が実行時にプレースホルダー%sを変数nameで置き換えます。 複数の変数を文字列に加えたいときは、プレースホルダー1つにつきオブジェクト1つを含むタプルを%のあとに渡す必要があります。

# Assigning variables.
>>> name = "Billy the Kid"
>>> fruit = "grapes"

# Building a string using %.
>>> "Surprisingly, %s's favorite snack was %s." %(name, fruit)
"Surprisingly, Billy the Kid's favorite snack was grapes."

テンプレート文字列

string.Template()(Python 3.14のt-stringsと混同しないでください)は、stringモジュール(組み込みのstr型とは別です)のクラスです。Python標準ライブラリの一部ですが、使うにはインポートする必要があります。 テンプレート文字列は$による置換をサポートしており、ここで挙げた他の方法よりずっと単純で、できることも少なめです。 ただし、複雑な国際化や外部入力のサニタイズにはとても役立ちます。

string.Templateは、信頼できないユーザー入力に対してより安全だと考えられています。任意の式の評価やオブジェクトの属性へのアクセスを防ぐため、フォーマット文字列インジェクション攻撃を軽減できるからです。

>>> from string import Template

>>> name = "Anna-Conda"

# Creating a Template with placeholder text.
>>> template_string = Template("The snake called `$snake_name` has escaped!")

# Calling .substitute() to replace the placeholder with a value.
>>> template_string.substitute(snake_name=name)
'The snake called `Anna-Conda` has escaped!'

string.Templateの詳細はPythonのドキュメントにあります。

どのフォーマット方法を選べばよいのでしょうか?

これだけ選択肢とミニ言語があると、Pythonの文字列をフォーマットするときに何を使えばよいか、どう決めればよいのでしょうか? 手早く判断できる簡単な指針を挙げます:

  1. f-stringは最も新しく、最も読みやすい方法です。 国際化が不要なら、Python 3.6以降では第一に選びたい方法です。

  2. str.format()は汎用性が高く、強力で、gnu gettextやほとんどのバージョンのPythonと互換性があります。

  3. 単純さ、安全性、あるいは本格的な国際化が必要なら、string.Template()を使うと、ユーザーからの入力を扱うときのリスクを軽減でき、翻訳文字列のラップにも使えます。

  4. %演算子は、新しいコードでは一般に非推奨とされていますが、現代のPythonでも動きます。 主に古いコードベースとの互換性のために使うものだと考えてください。 %フォーマットは他の方法より間違いを招きやすく(機能も少なく)、非ASCII文字の表示で問題を起こすことがあります。 使うつもりなら、お使いのPythonディストリビューションの対応状況を確認してください。

さらに深く学びたいなら、all about formattingとPython String Formatting Best Practicesが良い出発点になります。

GitHubで編集 リンクは新しいウィンドウまたはタブで開きます