Session State
Session State provides a dictionary-like interface where you can save information that is preserved between app reruns. The session is accessible using st.session_state.
You can store or access the values from session state, using key (st.session_state["my_key"]) or attribute notation (st.session_state.my_key).
NOTE
Session state also persists across pages inside a multipage app.
What is a session
A session is a single instance of viewing an app. If you view an app from two different tabs in your browser, each tab will have its own session. So, each viewer of the app will have a Session State tied to their specific view. Streamlit maintains the session as the user interacts with the app. If the user refreshes their browser page or reloads the URL to the app, their Session State resets and they begin again with a new session.
Widget State
Streamlit widgets are stateful by default. That is, Streamlit automatically stores the state of its widgets (like sliders, buttons, text inputs, etc.) between reruns. Consider this example:
import streamlit as st
# Slider widget
x = st.slider('x')
print(f"New value of x: {x}")
# Button to trigger app rerun
st.button("Click me")When you change the slider value, the app will rerun from top to bottom due to user interaction and you'll see the new
xvalue printed to console.Even when you click the button, which would cause the app to rerun, the widget value isn't going to reset. This is because Streamlit maintains the state of the widgets across reruns.
Why use Session State
When you want to persist any state across reruns, you should use session state. Although widgets are stateful by default, you can't manage their values from a different component. Consider this example:
import streamlit as st
x = st.slider('x')
if st.button("Click to increment"):
x += 1
print(f"New value of x: {x}")When you click the button, the slider value is incremented, but because of the user interaction, the app reruns from top to bottom and resets the value of
xback to the widget state, and so you won't be able to see any change on the web UI. But on the console, you'll be able to see thatxis incremented by 1, everytime the button is clicked.
This is because incrementing the slider value in this way doesn't update the widget's state directly. To achieve the desired behavior, you should use session state. Now consider this updated example:
import streamlit as st
if st.button("Click to increment"):
st.session_state.slider_x += 1
x = st.slider('x', key='slider_x')
print(f"New value of x: {x}")Here we're using session state to manage slider widget value, using the
keyargument. Now, everytime the button is clicked, the widget value automatically increments by 1.
IMPORTANT
Streamlit does not allow setting widget values via the Session State API for st.button and st.file_uploader.
Note that the slider state can't be modified after it is instantiated with the key argument. This is because of the Streamlit's execution from top to bottom on app reruns. So when the button is clicked, the slider gets rendered before the session state is updated, which is why the slider can't reflect the updated value. For example:
import streamlit as st
x = st.slider('x', key='slider_x')
if st.button("Click to increment"):
st.session_state.slider_x += 1
print(f"New value of x: {x}")The above code will cause an exception
StreamlitAPIExceptionon button click.
But what if you need the button below the slider widget? This is where Callbacks come into play.
Callbacks
Session state can also be updated using Callbacks. A callback is a python function which gets called when a widget changes. Here is the above example updated with a callback:
import streamlit as st
x = st.slider('x', key='slider_x')
def increment_slider():
st.session_state.slider_x += 1
st.button("Click to increment", on_click=increment_slider)
print(f"New value of x: {x}")Order of execution
You may be wondering how callback worked, despite the Streamlit app rerunning from top to bottom.
When updating Session state in response to events, a callback function gets executed first, and then the app is executed from top to bottom. This allows you to place widgets anywhere in your code while still being able to change the state without exceptions.
args and kwargs
Callbacks support passing arguments using the args and kwargs parameters in a widget.
# args example
# ... other code
increment_value = st.number_input('Enter a value', value=0, step=1)
def increment_slider(increment_value):
st.session_state.count += increment_value
increment = st.button('Increment', on_click=increment_slider, args=(increment_value, ))
# ... other code# kwargs example
# ... other code
def increment_slider(increment_value=0):
st.session_state.count += increment_value
increment = st.button('Increment', on_click=increment_slider, kwargs=dict(increment_value=5))
# ... other codeSerializable Session State
Serialization refers to the process of converting an object or data structure into a format that can be persisted and shared, and allowing you to recover the data’s original structure. Python’s built-in pickle module serializes Python objects to a byte stream ("pickling") and deserializes the stream into an object ("unpickling").
By default, Streamlit’s Session State allows you to persist any Python object for the duration of the session, irrespective of the object’s pickle-serializability. However, since not all execution environments support this, you can enable the runner.enforceSerializableSessionState configuration option to make Session State automatically use the pickle module for serialization.
