サイトアイコン アマチュア無線局JS2IIU

【Streamlit】st.session_stateの初期化を関数化して整理する方法

こんにちは、JS2IIUです。
Streamlitでアプリを開発していると、ユーザーの状態(セッション状態)を保持するために st.session_state を使うことが多くなります。

小さなアプリでは問題ありませんが、扱う状態が多くなるにつれて「初期化が煩雑」「どこで何を定義したか分からなくなる」といった問題が発生しやすくなります。

この記事では、セッション状態の初期化処理を関数化してアプリの構造を整理する方法を、ステップバイステップで丁寧に解説します。

✅ st.session_stateとは?(簡単なおさらい)

st.session_state は、Streamlitアプリにおいてセッション(ユーザー単位)で変数を保持できる仕組みです。

たとえば、ボタンを押すたびにカウントアップするカウンターを作りたいとき、以下のように使います。

Python
import streamlit as st

# 初期化
if 'count' not in st.session_state:
    st.session_state.count = 0

# ボタンが押されたらカウントアップ
if st.button('カウントアップ'):
    st.session_state.count += 1

# カウントの表示
st.write(f"現在のカウント: {st.session_state.count}")

このように st.session_state を使うと、ページを再読み込みしない限り値を保持できます。

🔧 セッション状態の初期化が煩雑になるケース

アプリの規模が大きくなってくると、状態管理の変数が増えて、次のようなコードになります:

Python
if 'page' not in st.session_state:
    st.session_state.page = 'home'

if 'counter' not in st.session_state:
    st.session_state.counter = 0

if 'data' not in st.session_state:
    st.session_state.data = []

if 'flag' not in st.session_state:
    st.session_state.flag = False

このように、変数が増えるたびに似たような初期化コードを書く必要があり、非常に煩雑になります。

✅ 初期化処理を関数化する方法【ステップ1】

これを解決するために、初期化処理を一か所にまとめておける関数を作りましょう。名前はたとえば initialize_session_state() とします。

Python
def initialize_session_state():
    defaults = {
        'page': 'home',
        'counter': 0,
        'data': [],
        'flag': False,
    }
    for key, value in defaults.items():
        if key not in st.session_state:
            st.session_state[key] = value

この関数では、辞書 defaults に初期値をまとめておき、キーが存在しないときだけ設定するようにしています。

これにより、どのキーを使っているか、どんな初期値なのかが一目で分かるようになり、保守性が向上します。

🧪 関数を使った全体コード【ステップ2】

それでは、先ほどの関数を使って、実際のStreamlitアプリを作ってみましょう。

Python
import streamlit as st

# 初期化関数
def initialize_session_state():
    defaults = {
        'page': 'home',
        'counter': 0,
        'data': [],
        'flag': False,
    }
    for key, value in defaults.items():
        if key not in st.session_state:
            st.session_state[key] = value

# 初期化処理の呼び出し
initialize_session_state()

# アプリの表示
st.title("セッション状態の管理アプリ")

st.write(f"現在のページ: {st.session_state.page}")
st.write(f"カウント: {st.session_state.counter}")
st.write(f"データ: {st.session_state.data}")
st.write(f"フラグ: {st.session_state.flag}")

if st.button("カウントアップ"):
    st.session_state.counter += 1

if st.button("フラグをトグル"):
    st.session_state.flag = not st.session_state.flag

このようにすれば、状態の初期化を関数で一元管理でき、UIのコードと混在せず、見通しの良いアプリ構成になります。

📦 応用:初期化をモジュール化する【ステップ3】

さらにアプリの規模が大きくなってきたら、初期化関数を外部ファイルに分けてモジュールとして管理するのもおすすめです。

たとえば、session_utils.py というファイルを作成して以下のように書きます:

Python
# session_utils.py

def initialize_session_state(st):
    defaults = {
        'page': 'home',
        'counter': 0,
        'data': [],
        'flag': False,
    }
    for key, value in defaults.items():
        if key not in st.session_state:
            st.session_state[key] = value

そして、メインファイル側では次のように使います:

Python
import streamlit as st
from session_utils import initialize_session_state

initialize_session_state(st)

こうすることで、状態管理ロジックを完全に分離でき、アプリ本体をスッキリ保つことができます。

💡 外部モジュール側のコード(session_utils.py)解説:

💡 メインアプリ側のコード解説:

❓ なぜ引数で st を渡すのか?

以下の理由で引数化するとメリットがあります:

理由説明
依存性の明示外部モジュールで import streamlit をしないので、関数の依存対象が明確になります。
テストしやすいst の代わりにモックオブジェクトを渡せば、単体テストが可能になります。
柔軟性の向上他のUIモジュールに切り替える際にも再利用性が高まります。

✅ まとめ

🔗 参考リンク

最後まで読んでいただきありがとうございます。

モバイルバージョンを終了