mei_13のPython講座 ロゴ

【解説】Pythonでデータの階層構造を美しく描く:ツリー図の基本と実装




🐍 初心者歓迎!月額4,000円で質問し放題のPython講座
(1時間4,000円の伴走型ビデオチャット指導も受付中!)
🚀 講座の詳細を見る 📩 質問・お問い合わせ

Pythonでデータの階層構造を美しく描く:ツリー図の基本と実装


Hirokiのアイコン
【Hiroki】 Yukiさん、こんにちは! 最近、自分のPCのフォルダを整理するプログラムをPythonで作ってみようと思っているんです。 でも、フォルダの中にまたフォルダがあって……という階層構造を、コマンドプロンプトやターミナルで見る「ツリー形式」で綺麗に表示する方法がわからなくて。 Pythonで、ああいう「ツリー図」って簡単に作れるものなんでしょうか?


Yukiのアイコン
【Yuki】 Hirokiくん、こんにちは。 フォルダの階層構造を視覚化するのは、プログラムの動作を確認したり、データの全体像を把握したりするのにとても大切ですよね。 「ツリー図」は、一見すると複雑そうに見えるかもしれませんが、Pythonの基本的な考え方である「再帰」を理解すると、意外とシンプルに作ることができるんですよ...。 今日は、標準ライブラリを使った基本的な方法から、外部ライブラリを使って見た目を綺麗にする方法まで、いくつか紹介してみたいと思います。 わたしも、夜中に静かな環境でコードの構造をじっと眺めていると、データが生きているような感じがして、なんだか落ち着くことがあります...。 ゆっくり進めていきましょうね。

木構造(ツリー構造)の考え方


Hirokiのアイコン
【Hiroki】 「木構造」って、ITの用語でよく聞きますよね。 でも、具体的にどういう仕組みなのか、実はあやふやなところがあって……。


Yukiのアイコン
【Yuki】 そうですね...。木構造というのは、1つの「根(ルート)」から枝分かれして、データが広がっていく形式のことです。 家系図や、Hirokiくんが言ったフォルダの構造がまさにそうですね。 一番上のフォルダがあって、その中にサブフォルダ(子)があり、さらにその中にファイル(葉)がある……という形です。 これをプログラムで表現するとき、もっとも一般的なのが「再帰処理(さいきしょり)」という手法です。 「関数の中で、自分自身をもう一度呼び出す」という方法なのですが、これがツリー図を作る上での鍵になると思います...。


Hirokiのアイコン
【Hiroki】 自分自身を呼び出す……。ちょっと難しそうですが、コードで見るとわかりやすいでしょうか?


Yukiのアイコン
【Yuki】 そうかもしれませんね。まずは、Pythonに最初から入っている os モジュールを使って、簡単なディレクトリツリーを表示するコードを書いてみましょうか。 これは、誰かの役に立つために作られた小さな道具のような、とてもシンプルなプログラムです。

標準ライブラリ os を使った再帰的なツリー表示


Yukiのアイコン
【Yuki】 まずは、指定したディレクトリの中身を順番に見ていき、フォルダがあればその中をさらに見に行く、というプログラムを作ってみますね。

import os

def list_files(startpath, indent=''):
    # 指定されたパスの中にあるファイルとフォルダを取得します
    try:
        items = os.listdir(startpath)
    except PermissionError:
        # アクセス権限がない場合はスキップします
        return

    for i, item in enumerate(items):
        # これが最後の子要素かどうかを判定します
        is_last = (i == len(items) - 1)

        # 枝の記号を決定します
        if is_last:
            marker = '└── '
            next_indent = indent + '    '
        else:
            marker = '├── '
            next_indent = indent + '│   '

        print(f'{indent}{marker}{item}')

        # フォルダの場合は、自分自身を呼び出して(再帰)中身を表示します
        path = os.path.join(startpath, item)
        if os.path.isdir(path):
            list_files(path, next_indent)

# 実行例(現在のディレクトリを表示する場合)
# list_files('.')


Hirokiのアイコン
【Hiroki】 おお……! ├── とか └── が付くと、一気にツリー図っぽくなりますね! でも、この list_files(path, next_indent) の部分で、また自分を呼び出しているのが不思議です。


Yukiのアイコン
【Yuki】 そこが再帰の面白いところです...。 「フォルダを見つけたら、その中身に対しても同じルールを適用する」という命令を繰り返しているんですね。 一番深いところまで行くと、もうフォルダがないので自然に処理が終わり、一つ上の階層に戻っていきます。 こうした小さなツールは、目立たないけれど誰かの作業を支えるために存在していて……。 わたしも、こういう健気なコードを書いていると、少しだけ自分も誰かの体の一部になって支えられているような、不思議な安心感を感じることがあります...。

pathlib モジュールを使ったモダンな書き方


Hirokiのアイコン
【Hiroki】 os モジュール以外にも方法はありますか? 最近は pathlib というのが推奨されていると聞いたのですが。


Yukiのアイコン
【Yuki】 さすがHirokiくん、よく勉強していますね。 pathlib は、パスをオブジェクトとして扱えるので、コードがより直感的で読みやすくなると思います...。 同じような処理を pathlib で書くと、このようになります。

from pathlib import Path

def tree(directory):
    print(f'+ {directory.name}/')
    # rglob('*') でサブディレクトリまで含めて全て取得できます
    # ですが、今回は構造を制御するために iterdir() を使うのが一般的かもしれません
    walk_path(Path(directory), "")

def walk_path(path, prefix):
    # 中身をリスト化して取得します
    contents = list(path.iterdir())
    pointers = ['├── '] * (len(contents) - 1) + ['└── ']

    for pointer, path in zip(pointers, contents):
        print(f'{prefix}{pointer}{path.name}')
        if path.is_dir():
            # 枝の表示を調整して再帰呼び出し
            extension = '    ' if pointer == '└── ' else '│   '
            walk_path(path, prefix + extension)

# 使い方
# tree(Path('sample_folder'))


Hirokiのアイコン
【Hiroki】 pathlib の方が、フォルダかどうかを判定する path.is_dir() といった書き方が自然でわかりやすい気がします。


Yukiのアイコン
【Yuki】 そうですね、文字列の操作が減るので、間違いも少なくなると思います...。 ただ、こうした自作の関数も良いのですが、もっと「見た目」にこだわりたいときは、既存のライブラリに頼るのも一つの手ですよ。

ライブラリ rich で豪華なツリー図を作る


Hirokiのアイコン
【Hiroki】 「見た目」ですか! ぜひ知りたいです。


Yukiのアイコン
【Yuki】 Pythonには rich という、ターミナルでの表示を美しくするためのライブラリがあります。 これを使うと、色をつけたり、アイコンのような表示をしたりすることも簡単にできるんです...。 少しだけ、使い方の例をお見せしますね。

# pip install rich でインストールが必要です
from rich.tree import Tree
from rich import print
import os

def build_rich_tree(dir_path, tree_node):
    # 指定したディレクトリ内のファイルとフォルダを走査します
    try:
        items = sorted(os.listdir(dir_path))
    except PermissionError:
        return

    for item in items:
        path = os.path.join(dir_path, item)
        if os.path.isdir(path):
            # フォルダなら新しいノード(枝)を追加して再帰
            branch = tree_node.add(f"[bold magenta]:open_file_folder: {item}[/bold magenta]")
            build_rich_tree(path, branch)
        else:
            # ファイルなら葉を追加
            tree_node.add(f"[green]:page_facing_up: {item}[/green]")

# 実行
# my_tree = Tree("[bold blue]Root Directory[/bold blue]")
# build_rich_tree(".", my_tree)
# print(my_tree)


Hirokiのアイコン
【Hiroki】 すごい! 色がついているし、フォルダのアイコン(絵文字)まで出てきました! これなら、一目でどこに何があるか分かりますね。


Yukiのアイコン
【Yuki】 ふふ、喜んでもらえてよかったです...。 rich ライブラリは非常に多機能で、フォントのスタイルや色を細かく設定できるんです。 データの並びが整っていると、夜もぐっすり眠れるような……そんな気持ちになりませんか? ……あ、わたしは夜行性なので、起きてはいるのですが。 とにかく、情報の「整理整頓」は、プログラムを読みやすくする第一歩だと思います。

rich documentation

汎用的なデータ構造を扱う anytree


Hirokiのアイコン
【Hiroki】 今までは「ファイル」の構造でしたが、例えば「ゲームのキャラクターの進化表」とか「組織図」みたいな、ファイル以外のデータをツリー図にしたい場合はどうすればいいんでしょうか?


Yukiのアイコン
【Yuki】 その場合は、anytree というライブラリが便利かもしれません...。 これはファイルシステムに限らず、あらゆる「親子関係」を持つデータを扱うために設計されています。 使い方もとてもシンプルですよ。

# pip install anytree でインストールが必要です
from anytree import Node, RenderTree

# ノード(節)を定義します
root = Node("勇者")
sub1 = Node("戦士", parent=root)
sub2 = Node("魔法使い", parent=root)
leaf1 = Node("ナイト", parent=sub1)
leaf2 = Node("パラディン", parent=sub1)
leaf3 = Node("賢者", parent=sub2)

# ツリーを表示します
for pre, fill, node in RenderTree(root):
    print(f"{pre}{node.name}")


Hirokiのアイコン
【Hiroki】 parent=root みたいに指定するだけで、勝手につながってくれるんですね! これなら、僕でも簡単に家系図とかを作れそうです。


Yukiのアイコン
【Yuki】 ええ、きっと大丈夫だと思います。 複雑なデータも、こうして視覚化してみると、意外なつながりが見えてきたりして面白いですよ...。 anytree は、属性を自由に追加できるので、「HP」や「攻撃力」などのデータを持たせることも可能です。

anytree documentation

まとめとアドバイス


Hirokiのアイコン
【Hiroki】 Yukiさん、ありがとうございます! 標準ライブラリでの作り方から、便利なライブラリまで知ることができて、ツリー図がぐっと身近になりました。 まずは os モジュールで自分でロジックを組んでみて、慣れてきたら rich でかっこいいツールを作ってみようと思います。


Yukiのアイコン
【Yuki】 それがいいと思います...。 まずは仕組みを理解するために、自分でコードを書いてみるのは、とても大切な経験になるはずです。 もし途中でエラーが出たり、枝の表示がズレてしまったりしても、あまり落ち込まないでくださいね。 プログラムも、木と同じように、ゆっくりと時間をかけて育てていけばいいんですから。


Hirokiのアイコン
【Hiroki】 はい! 頑張ってみます。 Yukiさんの説明、いつも丁寧で分かりやすくて助かります。


Yukiのアイコン
【Yuki】 そんなふうに言ってもらえると、少し恥ずかしいですが……とても嬉しいです...。 わたしは、こうした小さな工夫で誰かの世界が少しだけ便利になる、そんなツールの話が大好きなんです。 また分からないことがあったら、いつでも聞いてくださいね。 わたしは静かなところで、いつでもHirokiくんの学びを応援しています。


Hirokiのアイコン
【Hiroki】 ありがとうございます、Yukiさん!


Yukiのアイコン
【Yuki】 ……あ、最後にもう一つだけ。 もし余裕があったら、自分で作ったツリー図をテキストファイルに書き出す機能も付けてみると、記録として残せて便利かもしれません...。 「アウトプット」を形に残すのは、とても素敵なことだと思いますから。 それでは、また。



< オブジェクト指向
コラム一覧に戻る
Anaconda >

この記事では基礎を解説しましたが、実務においては「もっと複雑なデータを扱いたい」「独自のシステムに組み込みたい」といった、個別の課題に直面することも多いはずです。

「自分で書く時間は最小限に抑え、プロの品質でツールを完成させたい」という方は、ぜひ一度ご相談ください。

「教わる」だけでなく「形にする」パートナーとして、フリーランスエンジニアのmei_13が最短ルートでの解決をサポートします。

➡ ココナラで制作・相談を依頼する(見積もり無料)


初心者から始められるPythonレッスン

プログラミング未経験者・初心者歓迎!
月額4,000円で質問し放題!!
● 完全オンライン
● 翌日までには必ず返信
● 挫折しない独自の学習メソッド
● 圧倒的高評価!!
テキストベースで時間を選ばない
4,000円/60分伴走型ビデオチャット指導も可能
● 高品質なサンプルコード
詳細はこちら

📩 質問・お問い合わせはこちら



AIアシスタント Yuki