こんにちは、JS2IIUです。
今回は、Streamlitの便利な機能 st.session_state に、単純な値だけでなく、辞書やリストなどの複雑なデータを持たせる方法を丁寧に解説します。
1. そもそも st.session_state って何?
StreamlitはWebアプリを簡単に作れるPythonのライブラリですが、ページが更新されるたびにプログラムは最初から実行されます。
そのため、ユーザーの操作で入力した値やデータは普通に書くだけでは保持されません。
ここで役立つのが st.session_state です。
これは「セッション(接続)ごとの状態を保存しておく辞書のようなもの」と考えてください。
- ユーザーが入力したデータを一時的に保存しておける
- ページの再読み込みがあっても状態を保持できる
これにより、ユーザー体験を途切れさせずにアプリを作れます。
2. st.session_state に単純な値(スカラー値)を保存する基本例
まずは、簡単な文字列や数値の保存例を見てみましょう。
import streamlit as st
# 初期値を設定(キーがなければ)
if 'counter' not in st.session_state:
st.session_state.counter = 0
# ボタンを押したらカウンターを増やす
if st.button('カウントアップ'):
st.session_state.counter += 1
st.write(f"カウンターの値:{st.session_state.counter}")このコードでは、counter という単純な数値を st.session_state に保存しています。
ボタンを押すたびに増えていくのが分かりますね。
3. 辞書やリストなど複雑なオブジェクトを持たせたい理由
しかし、実際のアプリでは、もっと複雑な情報を一時的に保存したいことが多いです。
- 複数のフォームの入力内容をまとめて保存したい
- 表形式のデータを編集途中で保持したい
こうした時には、辞書やリストを使ってデータ構造を作り、st.session_state に保存します。
4. 辞書やリストを st.session_state に持たせる方法【基本編】
4-1. 初期化は必ずやろう
st.session_state はPythonの辞書に似ていますが、キーが存在しないとエラーになるので、まずは初期化が大事です。
if 'form_data' not in st.session_state:
st.session_state.form_data = {}このように、キーがなければ空の辞書をセットします。
4-2. 辞書やリストの更新は「直接変更」より「代入」が安全
Pythonの辞書やリストは「ミュータブル(変更可能)」ですが、Streamlitは状態の変化を検知するために「新しいオブジェクトを代入する」ことを推奨しています。
# NG例(動く場合もありますが推奨されません)
st.session_state.form_data['name'] = '太郎'
# OK例(辞書をコピーしてから変更)
data = st.session_state.form_data.copy()
data['name'] = '太郎'
st.session_state.form_data = data5. 実践例1:複数ステップの入力フォームを作る
5-1. 何を作る?
ユーザーが「名前」「年齢」「趣味」を別々のステップで入力し、全体を st.session_state の辞書にまとめて保存する例です。
5-2. コード全体
import streamlit as st
# 初期化
if 'form_data' not in st.session_state:
st.session_state.form_data = {}
if 'step' not in st.session_state:
st.session_state.step = 1
def next_step():
st.session_state.step += 1
def prev_step():
st.session_state.step -= 1
st.title("複数ステップ入力フォーム")
# ステップごとに表示するフォーム
if st.session_state.step == 1:
name = st.text_input("名前を入力してください", st.session_state.form_data.get('name', ''))
if st.button("次へ"):
data = st.session_state.form_data.copy()
data['name'] = name
st.session_state.form_data = data
next_step()
elif st.session_state.step == 2:
age = st.number_input("年齢を入力してください", min_value=0, max_value=120, value=st.session_state.form_data.get('age', 0))
col1, col2 = st.columns(2)
with col1:
if st.button("戻る"):
prev_step()
with col2:
if st.button("次へ"):
data = st.session_state.form_data.copy()
data['age'] = age
st.session_state.form_data = data
next_step()
elif st.session_state.step == 3:
hobby = st.text_input("趣味を入力してください", st.session_state.form_data.get('hobby', ''))
col1, col2 = st.columns(2)
with col1:
if st.button("戻る"):
prev_step()
with col2:
if st.button("送信"):
data = st.session_state.form_data.copy()
data['hobby'] = hobby
st.session_state.form_data = data
st.success("送信完了!")
st.write("入力内容の確認")
st.json(st.session_state.form_data)5-3. 解説
stepというキーで現在のフォームのステップを管理- 入力内容はすべて辞書
form_dataに保存 - ボタンでステップの前後移動が可能
- 各フォームの初期値は
form_dataから読み込み、入力内容を保持
6. 実践例2:表形式データの仮保存(リストのリストを管理)
6-1. 何を作る?
複数の商品の名前と価格を入力し、一時的にリストとして保存し画面で表示・編集できるシンプルなアプリです。
6-2. コード全体
import streamlit as st
# 初期化(商品リストは空リスト)
if 'items' not in st.session_state:
st.session_state.items = []
st.title("商品リストの編集")
with st.form("add_item_form"):
name = st.text_input("商品名")
price = st.number_input("価格", min_value=0, step=1)
submitted = st.form_submit_button("追加")
if submitted:
items = st.session_state.items.copy()
items.append({"name": name, "price": price})
st.session_state.items = items
st.success(f"商品「{name}」を追加しました!")
# 商品一覧表示
if st.session_state.items:
st.write("現在の登録商品:")
for i, item in enumerate(st.session_state.items):
col1, col2, col3 = st.columns([4, 2, 1])
col1.write(item['name'])
col2.write(f"{item['price']} 円")
if col3.button("削除", key=f"del_{i}"):
items = st.session_state.items.copy()
items.pop(i)
st.session_state.items = items
st.rerun() # 再実行して表示更新
else:
st.write("商品がまだ登録されていません。")6-3. 解説
itemsは辞書を要素に持つリストとしてst.session_stateに保存- フォームから商品名と価格を入力し、追加ボタンでリストに追加
- 登録済み商品は画面で一覧表示、削除ボタンで削除可能
- 状態をコピーして更新し、再実行で表示を最新化
7. まとめと注意点
st.session_stateは複雑なデータも保存できるが、初期化は必ず行うこと- ミュータブルな辞書やリストはコピーしてから代入しよう(直接編集はバグの元)
- 複数ステップフォームや表形式のデータ編集など、多様な応用が可能
- 状態管理がしっかりできることで、ユーザーにとって使いやすいアプリが作れる
参考
最後まで読んでいただきありがとうございます。

