roppong blog

[python3]ヒアドキュメントのTextwrap.dedent() が効かない

記事カテゴリ テクノロジー
投稿日: 2020年08月18日
random eye catch image

Jump to heading 事象

ヒアドキュメントの余計なインデントを無効化するために、Textwrap.dedent()を使用したが、
想定どおりに無効化されない。

Jump to heading 実行環境

root@f939e639fd93:~# python --version
Python 3.8.5

Jump to heading 期待する動作

test.py

def write_profile():
    profile_file_name = 'profile.txt'

    my_profile = """My name is {my_name}.
        I'm {age} years old.
        I like to {hobby}.""".format(my_name="roppong", age="31", hobby="run outside")

    with open(profile_file_name, 'w') as f:
        f.write(my_profile)

write_profile()

ヒアドキュメントで定義した文字列をファイルに書き込んだ結果、下記ファイルが作成されることを期待していた。

root@f939e639fd93:~# python test.py 
root@f939e639fd93:~# cat profile.txt
My name is roppong.
I'm 31 years old.
I like to run outside.

しかし、実際には、下記のような出力となった。

root@f939e639fd93:~# python test.py 
root@f939e639fd93:~# cat profile.txt 
My name is roppong.
        I'm 31 years old.
        I like to run outside.root@f939e639fd93:~# 

pythonファイルのインデントがそのままファイルに反映されている。
しかし、スクリプト上のインデントを解除すると、ソースコードの可読性が落ちてしまうためそれは避けたい。

インデントを無効化するために、Textwrap.dedent()を使用すればいいと分かった。

from textwrap import dedent を追加して、インデントを無効化したい文字列をdedent()に渡す。

Jump to heading 修正後1

test.py

from textwrap import dedent

def write_profile():
    profile_file_name = 'profile.txt'

    my_profile = """My name is {my_name}.
        I'm {age} years old.
        I like to {hobby}.""".format(my_name="roppong", age="31", hobby="run outside")

    with open(profile_file_name, 'w') as f:
        f.write(dedent(my_profile))

write_profile()

Jump to heading 結果1

root@f939e639fd93:~# python test.py
root@f939e639fd93:~# cat profile.txt 
My name is roppong.
        I'm 31 years old.
        I like to run outside.root@f939e639fd93:~# 

効かない。「dedent does not work」でググって、下記ページを見つける。

Textwrap.dedent() does not work

dedentの仕様上、2行目以降のインデントは、1行目のインデントの情報を引き継ぐらしい。
ということで、ヒアドキュメントのクォート3つの後に、pythonのインデント2つ分(空白8つ)を入れる。

Jump to heading 解決策

Jump to heading 修正後2

test.py

from textwrap import dedent

def write_profile():
    profile_file_name = 'profile.txt'

    my_profile = """        My name is {my_name}.
        I'm {age} years old.
        I like to {hobby}.
        """.format(my_name="roppong", age="31", hobby="run outside")

    with open(profile_file_name, 'w') as f:
        f.write(dedent(my_profile))

write_profile()

これで、もともと欲しかったファイルを得ることができた。