python

Pythonの文字列生成いろいろ

Pythonで文字列を結合したりフォーマット(文字列に変数値を入れること)する方法について、自分の知識に偏りを感じたので一通り調べてまとめました。

知らなくても問題なさそうな部分は除外しつつ広く網羅しています。

+演算子による結合

文字列と文字列は+演算子を使って結合できます。

'あいうえお' + 'かきくけこ'

結果:

'あいうえおかきくけこ'

変数同士の結合

a = 'あいうえお'
k = 'かきくけこ'
a + k

結果:

'あいうえおかきくけこ'

バックスラッシュを使った複数行結合

'あいうえお' + 'かきくけこ' + 'さしすせそ' \
 + 'たちつてと'

結果:

'あいうえおかきくけこさしすせそたちつてと'

ヒアドキュメントの結合

'あいうえお' + '''ヒアドキュメント
複数行も問題なし'''

結果:

'あいうえおヒアドキュメント\n複数行も問題なし'

文字列同士以外は結合不可

'あいうえお' + 3 # 3は文字列でないためエラーになる

結果:

TypeError: can only concatenate str (not "int") to str

文字列以外は文字列に変換してから結合

'あいうえお' + str(3) + repr(10)

結果:

'あいうえお310'

str(3)repr(3)は同じ'3'という戻り値を返しますが、str()関数はobject.__str__()関数が呼び出された戻り値、repr()関数はobject.__repr__()関数が呼び出された戻り値、という違いがあります。

__str__()関数と__repr__()関数を自作したオブジェクトに対して実験してみます。

class SampleObject:
    def __str__(self):
        return ' __str__の戻り値 '

    def __repr__(self):
        return ' __repr__の戻り値 '

obj = SampleObject()

str(obj) + repr(obj)

結果:

' __str__の戻り値  __repr__の戻り値 '

リテラル結合

文字列リテラル同士を隣に置くと、+演算子なしでも結合することができます。

'あいうえお' 'かきくけこ'

結果:

'あいうえおかきくけこ'

ヒアドキュメントの結合

'あいうえお' '''ヒアドキュメント
複数行も問題なし'''

結果:

'あいうえおヒアドキュメント\n複数行も問題なし'

複数行にわたって結合

改行文字をバックスラッシュ\でエスケープ

'あいうえお' 'かきくけこ'  \
'さしすせそ' 'たちつてと' \
'なにぬねの'

結果:

'あいうえおかきくけこさしすせそたちつてとなにぬねの'

()で囲ってバックスラッシュ\を省略

('あいうえお' 'かきくけこ'
'さしすせそ' 'たちつてと'
'なにぬねの')

結果:

'あいうえおかきくけこさしすせそたちつてとなにぬねの'

変数に代入されたものは結合できない

a = 'あいうえお'
k = 'かきくけこ'
a k

結果:

SyntaxError: invalid syntax

文字列を返す関数も結合できない

'あいうえお' str(3)

結果:

SyntaxError: invalid syntax

f文字列なら結合できる

k = 'かきくけこ'
'あいうえお' f'{k}' f'{3}'

結果:

'あいうえおかきくけこ3'

%スタイルフォーマット

%書式(フォーマット)を含む文字列に%演算子を使うこと、変数値で置換することができます。

このスタイルは推奨されておらず、後述する{}フォーマットやf文字列の使用が推奨されています。進んで使う必要はないものの、他の誰かが書いたプログラムを読んだり古いライブラリが使用を強制してきたりするため、ある程度知っておく必要ありです。

name = 'ケンヂまる'
'%sさん、こんにちは。' % name

結果:

'ケンヂまるさん、こんにちは。'

複数置換したい場合は、%演算子の後ろをタプルにします。

name = 'ケンヂまる'
times = 3
'%sさん、お会いするのは%d回目ですね。' % (name, times)

結果:

'ケンヂまるさん、お会いするのは3回目ですね。'

1つの置換の場合も、タプルが使えます。

'%sさん、こんにちは。' % (name, )

結果:

'ケンヂまるさん、こんにちは。'

文字列 or 整数 or 少数 などの型指定

name = '山田'
price = 2.5
count = 2
'%sさんは%fドルのジュースを%d本買った。' % (name, price, count)

結果:

'山田さんは2.500000ドルのジュースを2本買った。'

幅・0埋め・小数点以下桁数の制御

幅の指定

'私の名前は%8sです。' % name

結果:

'私の名前は      山田です。'

桁数の指定

'このジュースの値段は%5.2fドルです。' % price 

結果:

'このジュースの値段は 2.50ドルです。'

0埋め

'ジュース%02d本下さい。' % count

結果:

'ジュース02本下さい。'

アスタリスク'*'を使って桁数などを後から指定

'このジュースの値段は%0*.*fドルです。' % (8, 2, price)

結果:

'このジュースの値段は00002.50ドルです。'

dictで指定

my_dict = {'name': '山田', 'price': 2.5, 'count': 2}
'%(name)sさんは%(price)fドルのジュースを%(count)d本買った。' % my_dict

結果:

'山田さんは2.500000ドルのジュースを2本買った。'

dictで指定のうえ出力制御

'%(name)8sさんは%(price)07.2fドルのジュースを%(count)02d本買った。' % my_dict

結果:

'      山田さんは0002.50ドルのジュースを02本買った。'

{}スタイルフォーマット

str.format()関数を使うことで文字列の{}書式部分を置換することができます。

fmt = 'ケンヂまるは{}の呪文を唱えた'
fmt.format('ファイヤ')

結果:

'ケンヂまるはファイヤの呪文を唱えた'

複数置換

fmt = '{}は{}の呪文を唱えた。{}のダメージを与えた。'
fmt.format('ヂまる', 'ファイヤ', 0.5)

結果:

'ヂまるはファイヤの呪文を唱えた。0.5のダメージを与えた。'

{0} {1} {0} {2}

fmt = '{0}は{1}の呪文を唱えた。{0}は{2}のダメージを与えた。'
fmt.format('ヂまる', 'ファイヤ', 0.5)

結果:

'ヂまるはファイヤの呪文を唱えた。ヂまるは0.5のダメージを与えた。'

{player} {magic_word} {damage}

fmt = '{player}は{magic_word}の呪文を唱えた。{player}は{damage}のダメージを与えた。'
fmt.format(player='ヂまる', magic_word='ファイヤ', damage=0.5)

結果:

'ヂまるはファイヤの呪文を唱えた。ヂまるは0.5のダメージを与えた。'

dictを指定

my_dict = {
    'player': 'ヂまる', 
    'magic_word': 'ファイヤ', 
    'damage': 0.5}

fmt = '{player}は{magic_word}の呪文を唱えた。' \
          '{player}は{damage}のダメージを与えた。'
fmt.format(**my_dict)

結果:

'ヂまるはファイヤの呪文を唱えた。ヂまるは0.5のダメージを与えた。'

こちらも結果は同じ。

fmt = '{params[player]}は{params[magic_word]}の呪文を唱えた。' \
      '{params[player]}は{params[damage]}のダメージを与えた。'
fmt.format(params=my_dict)

さらにこちらも結果は同じ。

fmt = '{0[player]}は{0[magic_word]}の呪文を唱えた。' \
      '{0[player]}は{0[damage]}のダメージを与えた。'
fmt.format(my_dict)

オブジェクトのフィールドを指定

class Action:
    def __init__(self, player, magic_word, damage):
        self.player = player
        self.magic_word = magic_word
        self.damage = damage

fmt = '{0.player}は{0.magic_word}の呪文を唱えた。' \
        '{0.player}は{0.damage}のダメージを与えた。'
obj = Action('ヂまる', 'ファイヤ', 0.5)
fmt.format(obj)

文字列 or 整数 or 少数 などの型指定

fmt = '{:s}は{:s}の呪文を唱えた。' \
        '{:n}のMPを消費し{:f}のダメージを与えた。'
fmt.format('ケンヂまる', 'ファイヤ', 12, 0.5)

結果:

'ケンヂまるはファイヤの呪文を唱えた。12のMPを消費し0.500000のダメージを与えた'

幅・配置・0埋め・小数点以下桁数の制御

fmt = '{:<8s}は{:^8s}の呪文を唱えた。' \
        '{:03n}のMPを消費し{:.2f}のダメージを与えた。'
fmt.format('ケンヂまる', 'ファイヤ', 12, 0.5)

結果:

'ケンヂまる   は  ファイヤ  の呪文を唱えた。012のMPを消費し0.50のダメージを与えた。'

f文字列

文字列リテラルの先頭に「f」を付けることで、{}で囲った部分に変数値を直接埋め込むことができます。

player = 'ケンヂまる'
magic_word = 'ファイヤ'
f'{player}は{magic_word}の呪文を唱えた。'

結果:

'ケンヂまるはファイヤの呪文を唱えた。'

オブジェクトのメンバを埋め込む。

class Action:
    def __init__(self, player, magic_word, damage):
        self.player = player
        self.magic_word = magic_word
        self.damage = damage

obj = Action('ヂまる', 'ファイヤ', 0.5)

f'{obj.player}は{obj.magic_word}の呪文を唱えた。' \
        f'{obj.player}は{obj.damage}のダメージを与えた。'

結果:

'ケンヂまるはファイヤの呪文を唱えた。ケンヂまるは0.5のダメージを与えた。'

dictの値にアクセス

d = {
    'player': 'ケンヂまる',
    'magic_word': 'ファイヤ',
    'damage': 0.5
}

f'{d["player"]}は{d["magic_word"]}の呪文を唱えた。' \
        f'{d["player"]}は{d["damage"]}のダメージを与えた。'

結果:

'ケンヂまるはファイヤの呪文を唱えた。ケンヂまるは0.5のダメージを与えた。'

幅・配置・0埋め・小数点以下桁数の制御

player = 'ケンヂまる'
magic_word = 'ファイヤ'
mp_cost = 12
damage = 0.5

f'{player:<8s}は{magic_word:^8s}の呪文を唱えた。' \
        f'{mp_cost:02n}のMPを消費して{damage:.2f}のダメージを与えた。'

結果:

'ケンヂまる   は  ファイヤ  の呪文を唱えた。12のMPを消費して0.50のダメージを与えた。'

'='を使うとデバッグなどに便利な出力を作成することなどに活用できます。

'='を使うとデバッグなどで便利

player = 'ケンヂまる'
magic_word = 'ファイヤ'
mp_cost = 12
damage = 0.5

f'''{player = }
{magic_word = }
{mp_cost = }
{damage = }'''

結果:

player = 'ケンヂまる'
magic_word = 'ファイヤ'
mp_cost = 12
damage = 0.5

{}のネスト

damage = 0.5
precision = 3

f'{damage:.{precision}f}のダメージを与えた。'

結果:

'0.500のダメージを与えた。'

条件演算子

score = 79
f"試練の結果は{'合格' if score >= 80 else '不合格'}じゃ!"

結果:

'試練の結果は不合格じゃ!'

lambda式

score = 79
f"試練の結果は{(lambda x: x >= 80)(score)}じゃ!"

結果:

'試練の結果はFalseじゃ!'

算術演算

f'{1 + 2}'

結果:

'3'

論理演算

main_weapon = ''
sub_weapon = 'ロケットランチャー'

f'{main_weapon or sub_weapon}'

結果:

'ロケットランチャー'

ビット演算

f'{0b100 | 0b010}'

結果:

'6'

$テンプレート

stringモジュールのTemplateクラスを使用すると、文字列の${変数名}部分を置換することができます。

from string import Template

plate = Template('私の名前は${name}です。')
plate.substitute(name='ケンヂまる')

結果:

'私の名前はケンヂまるです。'

$変数名 形式

${変数名}ではなく$変数名でも問題なし。

plate = Template('私の名前は$nameです。')
plate.substitute(name='ケンヂまる')

結果:

'私の名前はケンヂまるです。'

ただしどこまで変数名か区別がつかない場合には問題になります。

plate = Template('私の名前は$name1号です。') # こちらは$name1と解釈されてエラー

plate = Template('私の名前は${name}1号です。')
plate.substitute(name='ケンヂまる')

結果:

'私の名前はケンヂまる1号です。'

dictで指定

d = {'name': 'ケンヂまる', 'number': 13}
plate = Template('私の名前は$name $number号です。')
plate.substitute(d)

結果:

'私の名前はケンヂまる 13号です。'

まとめ

  • +演算子で文字列の結合ができる。
  • 隣接した文字列リテラル同士は+演算子なしでも結合できる。
  • %スタイルは古いけど必要
  • {}スタイルやf文字列の使用が推奨
  • $テンプレートもある

-python

© 2024 ヂまるBlog