こんにちは、JS2IIUです。
Streamlitでアプリを開発していると、ユーザーの状態(セッション状態)を保持するために st.session_state を使うことが多くなります。
小さなアプリでは問題ありませんが、扱う状態が多くなるにつれて「初期化が煩雑」「どこで何を定義したか分からなくなる」といった問題が発生しやすくなります。
この記事では、セッション状態の初期化処理を関数化してアプリの構造を整理する方法を、ステップバイステップで丁寧に解説します。
✅ st.session_stateとは?(簡単なおさらい)
st.session_state は、Streamlitアプリにおいてセッション(ユーザー単位)で変数を保持できる仕組みです。
たとえば、ボタンを押すたびにカウントアップするカウンターを作りたいとき、以下のように使います。
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 を使うと、ページを再読み込みしない限り値を保持できます。
🔧 セッション状態の初期化が煩雑になるケース
アプリの規模が大きくなってくると、状態管理の変数が増えて、次のようなコードになります:
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() とします。
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アプリを作ってみましょう。
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 というファイルを作成して以下のように書きます:
# 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そして、メインファイル側では次のように使います:
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()のような関数を作って一元管理すると、可読性・保守性が大きく向上します。- 状態管理のロジックは、外部ファイルに分けるとさらに整理しやすくなります。
🔗 参考リンク
最後まで読んでいただきありがとうございます。

