0

0

在Streamlit中实现基于Pydantic和JSON的状态持久化教程

聖光之護

聖光之護

发布时间:2025-11-10 13:24:17

|

518人浏览过

|

来源于php中文网

原创

在streamlit中实现基于pydantic和json的状态持久化教程

本教程详细阐述了如何在Streamlit仪表板中实现健壮的状态持久化,通过结合Pydantic模型定义应用状态,并利用其高效的JSON序列化能力。我们将探讨如何将Pydantic模型与Streamlit的会话状态(st.session_state)集成,并通过回调函数在用户交互时自动保存状态到JSON文件,确保应用刷新或重新访问时能无缝加载先前配置。

1. 引言:Streamlit状态持久化的重要性

在开发交互式Streamlit仪表板时,管理和持久化应用状态是一个核心挑战。用户对参数进行调整、选择不同选项后,期望这些更改能在页面刷新或重新访问时得以保留。传统的Python变量在Streamlit应用重新运行时会重置,因此需要一种机制来保存这些状态。本教程将介绍如何利用Pydantic模型定义结构化的应用状态,并通过JSON文件实现其持久化,同时结合Streamlit的内置会话状态和回调机制,构建一个高效且易于维护的状态管理系统。

2. 使用Pydantic定义应用状态

Pydantic是一个强大的数据验证和设置管理库,非常适合用于定义Streamlit应用中的复杂状态结构。它允许我们以类型安全的方式定义数据模型,并提供了便捷的序列化/反序列化功能。

定义Pydantic模型:

首先,我们定义代表应用不同部分状态的Pydantic模型。例如,一个包含相机选择、裁剪参数和处理流程的仪表板状态可以这样定义:

import os
import json
from typing import List, Optional
from pydantic import BaseModel, Field

# 定义状态文件路径
STATE_PATH = os.path.join(os.getcwd(), 'application_state.json')

class SelectCameraState(BaseModel):
    """相机选择状态模型"""
    selected_cameras: List[str] = Field(default_factory=list)

class CropState(BaseModel):
    """裁剪参数状态模型"""
    crop_type: str = "Anchor"  # Anchor / Fixed
    bbox: List[int] = Field(default_factory=lambda: [0, 0, 100, 100])
    anchor_class: str = "default_class"
    anchor_position: List[int] = Field(default_factory=lambda: [50, 50])

class ProcessState(BaseModel):
    """处理流程状态模型"""
    feature_extractor: str = "ResNet"
    embedding_processor: str = "PCA"
    outlier_detector: str = "IsolationForest"

class ApplicationState(BaseModel):
    """整个应用的全局状态模型"""
    camera_select_state: SelectCameraState = Field(default_factory=SelectCameraState)
    crop_state: CropState = Field(default_factory=CropState)
    process_state: ProcessState = Field(default_factory=ProcessState)

    class Config:
        validate_assignment = True # 启用赋值验证

Pydantic的序列化优势:

Pydantic模型的一个关键优势是其内置的JSON序列化方法。与尝试在root_validator中手动处理可变对象(如列表)的更改不同,Pydantic提供了model_dump_json()方法,能够将整个模型及其嵌套的可变对象正确地序列化为JSON字符串。

# 示例:创建一个ApplicationState实例并序列化
initial_state = ApplicationState()
initial_state.camera_select_state.selected_cameras = ["Camera A", "Camera B"]
json_output = initial_state.model_dump_json(indent=2)
print(json_output)

3. 实现JSON文件的状态读写

为了实现状态持久化,我们需要将Pydantic模型序列化后的JSON字符串写入文件,并在应用启动时从该文件加载状态。

DALL·E 2
DALL·E 2

OpenAI基于GPT-3模型开发的AI绘图生成工具,可以根据自然语言的描述创建逼真的图像和艺术。

下载

状态加载函数:

def load_application_state() -> ApplicationState:
    """从JSON文件加载应用状态,如果文件不存在则返回默认状态。"""
    if os.path.exists(STATE_PATH):
        try:
            with open(STATE_PATH, 'r') as f:
                state_data = json.load(f)
            return ApplicationState.model_validate(state_data) # 使用model_validate进行反序列化
        except Exception as e:
            st.error(f"加载状态文件失败: {e},将使用默认状态。")
            return ApplicationState()
    return ApplicationState() # 文件不存在,返回默认状态

状态保存函数:

def save_application_state(state: ApplicationState):
    """将应用状态保存到JSON文件。"""
    try:
        with open(STATE_PATH, 'w') as f:
            f.write(state.model_dump_json(indent=2)) # 使用model_dump_json进行序列化
    except Exception as e:
        st.error(f"保存状态文件失败: {e}")

4. 结合Streamlit会话状态和回调机制

Streamlit提供了st.session_state作为内置的会话状态管理机制,它在用户会话期间保持数据不变。我们可以将Pydantic模型实例存储在st.session_state中,并通过Streamlit组件的on_change回调函数触发状态的保存。

集成流程:

  1. 初始化会话状态: 在Streamlit应用启动时,检查st.session_state中是否存在我们的ApplicationState实例。如果不存在,则从JSON文件加载或创建默认状态,并存储到st.session_state。
  2. 绑定回调函数: 将状态保存函数绑定到Streamlit组件的on_change参数。当用户与组件交互时,on_change回调会自动执行,更新st.session_state中的Pydantic模型,并将其保存到JSON文件。

完整示例:

import streamlit as st
import os
import json
from typing import List, Optional
from pydantic import BaseModel, Field

# 定义状态文件路径 (与前面相同)
STATE_PATH = os.path.join(os.getcwd(), 'application_state.json')

# 定义Pydantic模型 (与前面相同)
class SelectCameraState(BaseModel):
    selected_cameras: List[str] = Field(default_factory=list)

class CropState(BaseModel):
    crop_type: str = "Anchor"
    bbox: List[int] = Field(default_factory=lambda: [0, 0, 100, 100])
    anchor_class: str = "default_class"
    anchor_position: List[int] = Field(default_factory=lambda: [50, 50])

class ProcessState(BaseModel):
    feature_extractor: str = "ResNet"
    embedding_processor: str = "PCA"
    outlier_detector: str = "IsolationForest"

class ApplicationState(BaseModel):
    camera_select_state: SelectCameraState = Field(default_factory=SelectCameraState)
    crop_state: CropState = Field(default_factory=CropState)
    process_state: ProcessState = Field(default_factory=ProcessState)

    class Config:
        validate_assignment = True

# 状态加载和保存函数 (与前面相同)
def load_application_state() -> ApplicationState:
    if os.path.exists(STATE_PATH):
        try:
            with open(STATE_PATH, 'r') as f:
                state_data = json.load(f)
            return ApplicationState.model_validate(state_data)
        except Exception as e:
            st.error(f"加载状态文件失败: {e},将使用默认状态。")
            return ApplicationState()
    return ApplicationState()

def save_application_state_callback():
    """用于Streamlit on_change的回调函数,保存当前会话状态。"""
    if 'app_state' in st.session_state:
        save_application_state(st.session_state.app_state)

# --- Streamlit 应用主逻辑 ---

# 1. 初始化或加载应用状态到st.session_state
if 'app_state' not in st.session_state:
    st.session_state.app_state = load_application_state()

st.title("Streamlit仪表板状态持久化示例")

# 2. 显示和修改相机选择状态
st.header("相机选择")
available_cameras = ["Camera A", "Camera B", "Camera C", "Camera D"]
selected_cameras = st.multiselect(
    "选择相机",
    options=available_cameras,
    default=st.session_state.app_state.camera_select_state.selected_cameras,
    on_change=save_application_state_callback, # 绑定保存回调
    key="camera_multiselect" # 确保每个组件有唯一的key
)
# 更新Pydantic模型中的状态
st.session_state.app_state.camera_select_state.selected_cameras = selected_cameras

# 3. 显示和修改裁剪参数状态
st.header("裁剪参数")
crop_type_options = ["Anchor", "Fixed"]
crop_type = st.radio(
    "裁剪类型",
    options=crop_type_options,
    index=crop_type_options.index(st.session_state.app_state.crop_state.crop_type),
    on_change=save_application_state_callback, # 绑定保存回调
    key="crop_type_radio"
)
st.session_state.app_state.crop_state.crop_type = crop_type

bbox_col1, bbox_col2, bbox_col3, bbox_col4 = st.columns(4)
with bbox_col1:
    bbox_x = st.number_input("BBox X", value=st.session_state.app_state.crop_state.bbox[0], on_change=save_application_state_callback, key="bbox_x")
with bbox_col2:
    bbox_y = st.number_input("BBox Y", value=st.session_state.app_state.crop_state.bbox[1], on_change=save_application_state_callback, key="bbox_y")
with bbox_col3:
    bbox_w = st.number_input("BBox Width", value=st.session_state.app_state.crop_state.bbox[2], on_change=save_application_state_callback, key="bbox_w")
with bbox_col4:
    bbox_h = st.number_input("BBox Height", value=st.session_state.app_state.crop_state.bbox[3], on_change=save_application_state_callback, key="bbox_h")

st.session_state.app_state.crop_state.bbox = [bbox_x, bbox_y, bbox_w, bbox_h]

# 4. 显示和修改处理流程状态
st.header("处理流程")
feature_extractor = st.selectbox(
    "特征提取器",
    options=["ResNet", "VGG", "EfficientNet"],
    index=["ResNet", "VGG", "EfficientNet"].index(st.session_state.app_state.process_state.feature_extractor),
    on_change=save_application_state_callback,
    key="feature_extractor_select"
)
st.session_state.app_state.process_state.feature_extractor = feature_extractor

# 5. 显示当前完整状态 (用于调试)
st.subheader("当前应用状态 (实时更新)")
st.json(st.session_state.app_state.model_dump())

# 每次Streamlit脚本重新运行时,都会从st.session_state中获取状态,
# 而st.session_state在用户会话期间是持久的。
# 当用户改变UI组件时,on_change回调会触发,将最新的Pydantic模型保存到JSON文件。

5. 注意事项与最佳实践

  • Pydantic版本兼容性: 本教程使用model_dump_json()和model_validate(),这些方法在Pydantic v2及更高版本中引入。如果使用Pydantic v1,请使用json()和parse_obj()。
  • 回调函数的效率: on_change回调会在每次组件值变化时触发。对于频繁变化的组件(如滑动条),如果状态保存操作开销较大,可能会影响性能。可以考虑引入节流(throttling)或防抖(debouncing)机制,或者仅在关键操作后保存。
  • 错误处理: 在文件读写操作中加入try-except块,以优雅地处理文件不存在、读写权限问题或JSON格式错误等异常情况。
  • 文件路径管理: 确保STATE_PATH是可写且应用有权限访问的路径。在生产环境中,可能需要将状态文件存储在特定于用户的目录或数据库中,而不是应用根目录。
  • 安全性: 如果状态包含敏感信息,应考虑加密JSON文件或使用更安全的存储方案。
  • st.session_state的key参数: Streamlit组件需要唯一的key参数来正确管理其状态。在示例中,每个组件都分配了唯一的key。
  • 状态复杂性: 对于非常复杂或大型的状态,直接将整个Pydantic模型存储在JSON文件中可能不是最优解。可以考虑将部分状态存储在更专业的数据库中,而JSON文件仅用于存储用户偏好或配置。

6. 总结

通过结合Pydantic模型、JSON文件持久化以及Streamlit的会话状态和回调机制,我们能够构建一个强大且可靠的Streamlit应用状态管理系统。这种方法不仅保证了应用状态在刷新后的持久性,还通过Pydantic提供了类型安全和清晰的状态结构定义,极大地提高了代码的可维护性和健壮性。遵循本教程的指导,开发者可以有效地为他们的Streamlit仪表板添加高级状态持久化功能。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

419

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

535

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

311

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1501

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

624

2023.11.24

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号