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

Streamlit
この記事は約10分で読めます。

こんにちは、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)解説:

  • initialize_session_state(st):関数の引数として Streamlitモジュール全体 st を受け取る形になっています。
  • これは、外部ファイル内では import streamlit as st をせず、呼び出し元から渡すことで依存関係を明確化するためです。
  • defaults:初期化したいキーとデフォルト値の一覧を辞書で管理。拡張しやすく、可読性が高いです。
  • if key not in st.session_state::すでに値がある場合は上書きしない設計。再初期化を防ぐことで、意図しない値のリセットを防げます。

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

  • from session_utils import initialize_session_state:状態初期化の関数をインポートしています。
  • initialize_session_state(st):ここでStreamlitの st を引数として渡すことで、外部関数に session_state を操作させる権限を明示的に渡している形になります。

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

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

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

✅ まとめ

  • st.session_state はStreamlitでセッション状態を保持するのに便利な機能です。
  • 変数が多くなると初期化処理が煩雑になります。
  • initialize_session_state() のような関数を作って一元管理すると、可読性・保守性が大きく向上します。
  • 状態管理のロジックは、外部ファイルに分けるとさらに整理しやすくなります。

🔗 参考リンク

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

コメント

タイトルとURLをコピーしました