This is an experimental feature. Experimental features and their APIs may change or be removed at any time. To learn more, click here.
Function decorator to memoize function executions.
Memoized data is stored in "pickled" form, which means that the return value of a memoized function must be pickleable.
Each caller of a memoized function gets its own copy of the cached data.
You can clear a memoized function's cache with f.clear().
st.experimental_memo(func=None, *, persist=None, show_spinner=True, suppress_st_warning=False, max_entries=None, ttl=None, experimental_allow_widgets=False)
The function to memoize. Streamlit hashes the function's source code.
persist (str or boolean or None)
Optional location to persist cached data to. Passing "disk" (or True) will persist the cached data to the local disk. None (or False) will disable persistence. The default is None.
Enable the spinner. Default is True to show a spinner when there is a cache miss.
Suppress warnings about calling Streamlit commands from within the cached function.
max_entries (int or None)
The maximum number of entries to keep in the cache, or None for an unbounded cache. (When a new entry is added to a full cache, the oldest cached entry will be removed.) The default is None.
ttl (float or timedelta or None)
The maximum number of seconds to keep an entry in the cache, or None if cache entries should not expire. The default is None. Note that ttl is incompatible with persist="disk" - ttl will be ignored if persist is specified.
Allow widgets to be used in the memoized function. Defaults to False. Support for widgets in cached functions is currently experimental. Setting this parameter to True may lead to excessive memory use since the widget value is treated as an additional input parameter to the cache. We may remove support for this option at any time without notice.
import streamlit as st @st.experimental_memo def fetch_and_clean_data(url): # Fetch data from URL here, and then clean it up. return data d1 = fetch_and_clean_data(DATA_URL_1) # Actually executes the function, since this is the first time it was # encountered. d2 = fetch_and_clean_data(DATA_URL_1) # Does not execute the function. Instead, returns its previously computed # value. This means that now the data in d1 is the same as in d2. d3 = fetch_and_clean_data(DATA_URL_2) # This is a different URL, so the function executes.
To set the persist parameter, use this command as follows:import streamlit as st @st.experimental_memo(persist="disk") def fetch_and_clean_data(url): # Fetch data from URL here, and then clean it up. return data
By default, all parameters to a memoized function must be hashable. Any parameter whose name begins with _ will not be hashed. You can use this as an "escape hatch" for parameters that are not hashable:import streamlit as st @st.experimental_memo def fetch_and_clean_data(_db_connection, num_rows): # Fetch data from _db_connection here, and then clean it up. return data connection = make_database_connection() d1 = fetch_and_clean_data(connection, num_rows=10) # Actually executes the function, since this is the first time it was # encountered. another_connection = make_database_connection() d2 = fetch_and_clean_data(another_connection, num_rows=10) # Does not execute the function. Instead, returns its previously computed # value - even though the _database_connection parameter was different # in both calls.
A memoized function's cache can be procedurally cleared:import streamlit as st @st.experimental_memo def fetch_and_clean_data(_db_connection, num_rows): # Fetch data from _db_connection here, and then clean it up. return data fetch_and_clean_data.clear() # Clear all cached entries for this function.
Persistent memo caches currently don't support TTL.
ttl will be ignored if
persist is specified:
import streamlit as st @st.experimental_memo(ttl=60, persist="disk") def load_data(): return 42 st.write(load_data())
And a warning will be logged to your terminal:
$ streamlit run app.py You can now view your Streamlit app in your browser. Local URL: http://localhost:8501 Network URL: http://192.168.1.1:8501 2022-09-22 13:35:41.587 The memoized function 'load_data' has a TTL that will be ignored. Persistent memo caches currently don't support TTL.
st elements in cache-decorated functionsReplay static
Functions decorated with
@st.experimental_memo can contain static
st elements. When a cache-decorated function is executed, we record the element and block messages produced, so the elements will appear in the app even when execution of the function is skipped because the result was cached.
In the example below, the
@st.experimental_memo decorator is used to cache the execution of the
load_data function, that returns a pandas DataFrame. Notice the cached function also contains a
st.area_chart command, which will be replayed when the function is skipped because the result was cached.
import numpy as np import pandas as pd import streamlit as st @st.experimental_memo def load_data(rows): chart_data = pd.DataFrame( np.random.randn(rows, 10), columns=["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"], ) # Contains a static element st.area_chart st.area_chart(chart_data) # This will be recorded and displayed even when the function is skipped return chart_data df = load_data(20) st.dataframe(df)
st elements in cache-decorated functions include:
Replay input widgets in cache-decorated functions
In addition to static elements, functions decorated with
@st.experimental_memo can also contain input widgets! Replaying input widgets is disabled by default. To enable it, you can set the
experimental_allow_widgets parameter for
True. The example below enables widget replaying, and shows the use of a checkbox widget within a cache-decorated function.
import streamlit as st # Enable widget replay @st.experimental_memo(experimental_allow_widgets=True) def func(): # Contains an input widget st.checkbox("Works!") func()
If the cache decorated function contains input widgets, but
experimental_allow_widgets is set to
False or unset, Streamlit will throw a
CachedStFunctionWarning, like the one below:
import streamlit as st # Widget replay is disabled by default @st.experimental_memo def func(): # Streamlit will throw a CachedStFunctionWarning st.checkbox("Doesn't work") func()
How widget replay works
Let's demystify how widget replay in cache-decorated functions works and gain a conceptual understanding. Widget values are treated as additional inputs to the function, and are used to determine whether the function should be executed or not. Consider the following example:
import streamlit as st @st.experimental_memo(experimental_allow_widgets=True) def plus_one(x): y = x + 1 if st.checkbox("Nuke the value 💥"): st.write("Value was nuked, returning 0") y = 0 return y st.write(plus_one(2))
plus_one function takes an integer
x as input, and returns
x + 1. The function also contains a checkbox widget, which is used to "nuke" the value of
x. i.e. the return value of
plus_one depends on the state of the checkbox: if it is checked, the function returns
0, otherwise it returns
In order to know which value the cache should return (in case of a cache hit), Streamlit treats the checkbox state (checked / unchecked) as an additional input to the function
plus_one (just like
x). If the user checks the checkbox (thereby changing its state), we look up the cache for the same value of
x (2) and the same checkbox state (checked). If the cache contains a value for this combination of inputs, we return it. Otherwise, we execute the function and store the result in the cache.
Let's now understand how enabling and disabling widget replay changes the behavior of the function.
Widget replay disabled
- Widgets in cached functions throw a
CachedStFunctionWarningand are ignored.
- Other static elements in cached functions replay as expected.
Widget replay enabled
- Widgets in cached functions don't lead to a warning, and are replayed as expected.
- Interacting with a widget in a cached function will cause the function to be executed again, and the cache to be updated.
- Widgets in cached functions retain their state across reruns.
- Each unique combination of widget values is treated as a separate input to the function, and is used to determine whether the function should be executed or not. i.e. Each unique combination of widget values has its own cache entry; the cached function runs the first time and the saved value is used afterwards.
- Calling a cached function multiple times in one script run with the same arguments triggers a
- If the arguments to a cached function change, widgets from that function that render again retain their state.
- Changing the source code of a cached function invalidates the cache.
st.experimental_singletonsupport widget replay.
- Fundamentally, the behavior of a function with (supported) widgets in it doesn't change when it is decorated with
@st.experimental_singleton. The only difference is that the function is only executed when we detect a cache "miss".
All input widgets are supported in cache-decorated functions. The following is an exhaustive list of supported widgets: