LoginSignup
3
2

More than 3 years have passed since last update.

Streamlitでリストの初期化を防ぐ

Last updated at Posted at 2021-01-18

はじめに

備忘録です。
何か他にもいい方法があったら教えて下さい。

本題

Streamlitを使用すると、簡単に描画アプリを作成することができます。
また、Rerunボタンを押すことで、すぐにソースコードの変更を反映できます
スクリーンショット 2021-01-18 13.39.52.png

ここで問題が発生しました。
例えば以下のようにinputをリストで保持したい場合

import streamlit as st

lst = []
input = st.text_input('何か入力して下さい')
lst.append(input)
st.table(lst)

appの出力はこのようになります。
スクリーンショット 2021-01-18 13.50.09.png
ここで何かを入力してみます。
スクリーンショット 2021-01-18 13.52.37.png
aaaが反映されたことがわかります。
次に新しくbbbを追加してみます。
スクリーンショット 2021-01-18 13.53.34.png
bbbは追加されましたが、すでにあったaaaは反映されていませんでした。

なのでコードを修正してみました。チェックボックスがチェックされていると入力が止まるような
感じにしてみました。

lst = []
i = 0
while True:
    input = st.text_input('何か入力して下さい', key=str(i))
    lst.append(input)
    i += 1
    if st.checkbox('stop'):
        break
st.table(lst)

出力は以下のようになりました。
スクリーンショット 2021-01-18 13.59.25.png

streamlitで入力をループにするにはよくないっぽいです。(できたとしても入力欄が無限に出力されそう)

原因

原因としてはStreamlitでRerunを実行すると、全てのデータをロードしてしまうからでした。
Rerunはボタンを押さなくても、入力欄での追加・変更がされるだけでも自動的に行われます。
そこでStreamlitのcache機能を使用します。

Cacheとは

cacheはStreamlitのデコレーターです。
関数の前に@st.cacheをつけることで使用することができます。
簡単に言うとcacheを利用できるので、一度使った関数は引数が変わらないと変更が行われない感じです。
(変更される条件は他にも複数存在します。詳しくはドキュメントを参考にしてみて下さい。)

改善

それではcacheを使用してコードを変更してみます。

@st.cache(allow_output_mutation=True)
def cache_lst():
    lst = []
    return lst

lst = cache_lst()
input = st.text_input('何か入力して下さい')
if st.checkbox('clear'):
    caching.clear_cache()
    lst = cache_lst()
elif input:
    lst.append(input)
st.table(lst)

すると、以下のようにリストに値が保持できていることがわかります。
スクリーンショット 2021-01-18 14.58.41.png

また、clearのチェックボックスをチェックするとリストを初期化することができます。
これを使うことで、要素の削除や変更を行うことができます。
また、このときリストはimmutableなので、要素の変更を行う際に代入をする形をとると変更が反映されません。

@st.cache(allow_output_mutation=True)
def cache_lst():
    lst = []
    return lst

lst = cache_lst()
input = st.text_input('何か入力して下さい')
if st.checkbox('clear'):
    caching.clear_cache()
    lst = cache_lst()
elif input:
    lst.append(input)

if st.checkbox('delete'):
    delete = st.selectbox('削除する要素を選択して下さい', options=lst)
    if st.button('Delete'):
        lst.remove(delete)
        st.success(f'Delete : {delete}')

if st.checkbox('change'):
    change_from = st.selectbox('変更する要素を選択して下さい', options=lst)
    change_index = lst.index(change_from)
    change_to = st.text_input('何に変更しますか')
    if st.button('Change'):
        lst.remove(change_from)
        lst.insert(change_index, change_to)
        st.success(f'Change {change_from} to {change_to}')
st.table(lst)

スクリーンショット 2021-01-18 15.17.53.png
削除した時
スクリーンショット 2021-01-18 15.18.36.png
変更した時
スクリーンショット 2021-01-18 15.19.55.png
※削除・変更・追加をする際はinput欄に文字が入っていると勝手に追加されることがあるので注意して下さい

参考

Improve app performance
Streamlit入門

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2