简介这份资源是面向数据科学家与机器学习工程师的Streamlit入门实践包帮助零基础或初级开发者快速完成库的安装、环境配置与本地运行解决安装失败、依赖缺失、下载缓慢等常见问题。压缩包共4个文件约4KB包含2个Python脚本分别用于示例应用与安装测试、1个requirements.txt依赖清单和1个.inscode配置文件结构精简便于直接运行验证。已有80人学习下载适合希望把数据分析结果快速转成交互式Web应用、又不想深入全栈开发的工程师参考。读者可借助可运行源码复现安装流程对照依赖清单排查版本兼容问题利用测试脚本确认环境是否配置成功并参考加速技巧提升pip下载效率从而在较短时间内跑通第一个Streamlit应用为后续原型搭建与数据展示打下基础。1. Streamlit 安装运行指南从 pip 到浏览器一条命令跑通数据应用很多做数据分析的朋友卡在同一个地方模型和图表在 Jupyter 里跑得挺顺一旦要给别人看就得折腾前端、后端、部署三天过去页面还没影。Streamlit 就是冲着这个痛点来的——它把「写 Python 脚本」和「得到一个网页应用」之间的鸿沟压到几乎为零。你不需要懂 HTML、CSS、JavaScript也不用碰 Flask 路由只要会写st.write()浏览器里就能出现可交互的界面。这篇指南面向两类人刚听说 Streamlit、想在自己机器上跑通第一个应用的新手以及已经用过、但被环境冲突和缓存问题折腾过的熟手。接下来从安装、最小可运行源码、参数配置到排错一步步走完。2. 装之前先想清楚环境隔离与依赖版本怎么选2.1 为什么强烈建议用虚拟环境而不是全局 pipStreamlit 本身依赖不算重但它会连带拉起 Tornado、Altair、Pandas、Pillow 等一串包。如果你在系统全局 Python 里直接pip install streamlit很可能把某个已有项目的依赖版本顶掉——尤其是 Pandas 和 Protobuf这两个是版本冲突的重灾区。我见过最典型的翻车现场装完 Streamlit原来跑得好好的一个数据处理脚本突然报AttributeError查了半天发现是 Pandas 被降级了。所以第一步不是装 Streamlit而是先隔离。常见做法有三种venv、conda、pipenv。我一般用venv因为它随 Python 自带不额外引入工具链。命令如下# 创建虚拟环境目录名用 .venv 是社区惯例方便编辑器自动识别 python -m venv .venv # 激活环境Linux / macOS source .venv/bin/activate # 激活环境Windows PowerShell .venv\Scripts\Activate.ps1 # 激活后确认 python 指向虚拟环境内部 which python # Linux/macOS where python # Windows逻辑说明python -m venv .venv会在当前目录生成一个独立解释器副本和独立的site-packages。激活后后续所有pip install都只影响这个目录删掉.venv就等于彻底卸载不留残留。参数上.venv只是目录名你可以改成任何名字但用点开头能让它在文件列表里靠前、不碍眼。提示如果你用 VS Code 或 PyCharm创建完虚拟环境后记得在编辑器里手动切换解释器路径到.venv/bin/python否则编辑器提示的补全和实际运行环境会对不上。2.2 Python 版本与 Streamlit 版本的对应关系Streamlit 对 Python 版本有下限要求。较新的 Streamlit 版本通常要求 Python 3.8 及以上部分新特性会要求 3.9 或 3.10。如果你还在用 Python 3.7装最新版会直接失败报Requires-Python 3.8之类的错。这时候有两条路升级 Python或者锁定一个旧版 Streamlit。我的建议是优先升级 Python 到 3.10 或 3.11这两个版本在数据科学生态里兼容性最好。如果因为某些系统限制不能升级那就锁版本# 查看当前 Python 版本 python --version # 如果版本偏低安装一个兼容的旧版 Streamlit示例具体版本以实际可用为准 pip install streamlit1.30逻辑说明pip install streamlit1.30里的引号不能省否则会被 shell 当成重定向符号。这种写法叫版本约束pip 会在满足条件的范围内挑最新版。参数上1.30表示低于 1.30 的任意版本你也可以用1.28.0精确锁定。2.3 安装命令与国内网络下的加速方案环境准备好之后安装本身只有一行pip install streamlit但如果你在国内网络环境下直接从默认源拉包可能很慢甚至超时。这时候可以临时指定镜像源# 临时使用镜像源安装不修改全局配置 pip install streamlit -i https://pypi.tuna.tsinghua.edu.cn/simple # 或者永久配置写入 pip 配置文件后续所有安装都走镜像 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple逻辑说明-i参数指定本次安装使用的索引地址不影响其他项目。pip config set则是写配置文件一劳永逸但会影响所有 pip 操作。参数上镜像源地址可以根据自己网络情况替换常见的有清华、阿里、中科大等。装完之后用pip show streamlit确认版本和安装位置确保它落在虚拟环境里而不是全局。3. 最小可运行源码一个文件跑出可交互页面3.1 第一个 app.py 的完整代码与逐行解释Streamlit 应用的入口就是一个普通 Python 文件。新建app.py写入以下内容# app.py import streamlit as st import pandas as pd import numpy as np # 设置页面标题和布局这行必须在所有 st 命令之前调用 st.set_page_config(page_title销售数据看板, layoutwide) # 一级标题 st.title(销售数据看板) # 侧边栏放筛选控件 st.sidebar.header(筛选条件) region st.sidebar.selectbox( 选择区域, options[全部, 华东, 华北, 华南] ) # 生成模拟数据实际项目中替换为你的数据源 np.random.seed(42) data pd.DataFrame({ 区域: np.random.choice([华东, 华北, 华南], size200), 销售额: np.random.randint(1000, 10000, size200), 日期: pd.date_range(2024-01-01, periods200, freqD) }) # 根据侧边栏选择过滤数据 if region ! 全部: data data[data[区域] region] # 展示指标卡 col1, col2 st.columns(2) col1.metric(总销售额, f{data[销售额].sum():,}) col2.metric(记录数, len(data)) # 展示折线图 st.subheader(销售额趋势) daily data.groupby(日期)[销售额].sum() st.line_chart(daily) # 展示原始数据表格可折叠 with st.expander(查看原始数据): st.dataframe(data)逻辑说明Streamlit 的执行模型是「从头到尾重新运行整个脚本」。每次用户操作控件脚本都会重跑一遍所以代码里不需要写回调函数直接按顺序写逻辑即可。st.set_page_config必须放在第一个 st 命令之前否则会报错。st.sidebar把控件放到左侧栏st.columns做分栏布局st.expander做折叠面板。参数上layoutwide让页面占满宽度默认是居中窄布局。3.2 启动命令与浏览器访问在app.py所在目录下执行# 最简启动方式 streamlit run app.py # 指定端口和地址避免和已有服务冲突 streamlit run app.py --server.port 8502 --server.address 0.0.0.0逻辑说明streamlit run会启动一个本地 Web 服务默认监听 8501 端口并自动打开浏览器。如果 8501 被占用会报Port 8501 is already in use这时候用--server.port换一个端口。--server.address 0.0.0.0表示监听所有网卡适合在容器或远程机器上运行本地开发用默认的localhost就行。注意如果你在远程服务器上运行浏览器打不开localhost:8501需要用 SSH 端口转发把远程端口映射到本地或者用--server.address 0.0.0.0后通过服务器 IP 访问。具体转发方式取决于你的网络环境这里不展开。3.3 热重载机制与开发时的文件监听Streamlit 默认开启文件监听你修改app.py保存后页面右上角会出现「Rerun」提示点一下或按R键就能重新加载。如果没生效检查启动时是否带了--server.runOnSave false。另外Streamlit 只监听入口文件及其直接 import 的本地模块如果你把逻辑拆到多个文件里被 import 的文件改动也会触发重载但通过动态方式加载的文件不一定。# 显式开启保存时自动重载默认就是 true一般不用改 streamlit run app.py --server.runOnSave true逻辑说明热重载省去了手动重启服务的麻烦但要注意它重跑的是整个脚本如果你的脚本开头有耗时操作比如读大文件、训练模型每次改代码都会重新执行体验会很差。这时候就该上缓存了下一章细说。4. 参数配置与缓存让应用跑得快、不重复计算4.1 配置文件 config.toml 的常用参数Streamlit 支持用配置文件统一管理参数避免每次启动都敲一长串命令行。配置文件放在项目目录下的.streamlit/config.toml或者用户目录下的.streamlit/config.toml。项目级配置优先级更高。# .streamlit/config.toml [server] port 8501 address 0.0.0.0 runOnSave true maxUploadSize 200 [browser] gatherUsageStats false [theme] base light primaryColor #2E86AB逻辑说明[server]段控制服务行为maxUploadSize单位是 MB默认 200如果你要做文件上传功能且文件较大需要调高。[browser]段的gatherUsageStats设为 false 可以关闭使用数据上报。[theme]段自定义主题色primaryColor影响按钮和滑块的颜色。参数上这些值都可以被命令行参数覆盖命令行优先级高于配置文件。4.2 st.cache_data 与 st.cache_resource 的区别缓存是 Streamlit 性能优化的核心。它有两个装饰器st.cache_data和st.cache_resource。用错会导致要么缓存不生效要么出现诡异的共享状态问题。st.cache_data用于缓存「数据」——返回值是可序列化的对象比如 DataFrame、字典、列表。每次调用会复制一份返回值避免多个会话互相干扰。st.cache_resource用于缓存「资源」——比如数据库连接、模型对象、全局配置这些对象不适合复制多个会话共享同一个实例。import streamlit as st import pandas as pd # 缓存数据适合 DataFrame、计算结果 st.cache_data(ttl600) # ttl 单位秒600 秒后过期 def load_data(path): df pd.read_csv(path) return df # 缓存资源适合连接对象、模型 st.cache_resource def get_connection(): # 假设这里创建一个数据库连接 conn create_db_connection() return conn # 使用 df load_data(sales.csv) conn get_connection()逻辑说明ttl参数控制缓存过期时间不设则永不过期除非手动清除。st.cache_data的函数参数必须可哈希如果你传入的是列表或字典需要先转成元组或冻结集合。st.cache_resource没有 ttl 参数因为它缓存的是长生命周期对象。参数上show_spinnerFalse可以关闭缓存计算时的加载动画适合快速函数。4.3 缓存失效的三种触发条件与手动清除缓存不是永久有效的以下情况会触发重新计算函数参数变化、ttl 过期、手动调用st.cache_data.clear()。另外如果你修改了函数体代码Streamlit 会自动检测到并清空该函数的缓存。# 手动清除所有 cache_data 缓存 st.cache_data.clear() # 只清除特定函数的缓存 load_data.clear()逻辑说明手动清除适合在数据源更新后强制刷新。比如你有一个「刷新数据」按钮点击后调用load_data.clear()下次执行load_data()就会重新读文件。参数上clear()不接受参数调用即清空。注意st.cache_resource也有对应的clear()方法但一般不需要手动清除非连接失效需要重建。提示调试缓存问题时可以在函数里加一行st.write(正在计算...)如果每次操作都打印说明缓存没命中如果只打印一次说明缓存生效了。这是最直接的排查手段。5. 避坑与排查那些让新手卡半天的常见问题5.1 端口被占用导致启动失败现象执行streamlit run app.py后报OSError: [Errno 98] Address already in use或Port 8501 is already in use。原因8501 端口已经被另一个 Streamlit 实例或其他服务占用。常见于上次没正常关闭或者同时开了多个项目。解决换端口启动streamlit run app.py --server.port 8502或者找到占用进程杀掉。Linux/macOS 用lsof -i :8501查进程号Windows 用netstat -ano | findstr 8501。杀掉后重新启动即可。5.2 修改代码后页面不刷新现象改了app.py保存浏览器页面没变化右上角也没有 Rerun 提示。原因可能是文件监听没生效或者你改的文件不是入口文件直接 import 的模块。另外某些编辑器保存时先写临时文件再重命名可能导致监听丢失。解决先手动按R键或点右上角菜单里的 Rerun。如果还不行检查启动命令是否带了--server.runOnSave false。再不行就重启服务。我一般会在开发时保持终端可见看到Reloading...字样才确认监听正常。5.3 缓存导致数据不更新现象数据源文件已经改了但页面显示的还是旧数据。原因st.cache_data缓存了函数的返回值文件内容变化不会自动触发缓存失效因为函数参数文件路径没变。解决在读取函数里加上文件修改时间作为参数或者手动清除缓存。更优雅的做法是用ttl设置一个合理的过期时间。import os st.cache_data def load_data(path, mtime): # mtime 作为参数传入文件修改后 mtime 变化缓存自动失效 return pd.read_csv(path) path sales.csv mtime os.path.getmtime(path) df load_data(path, mtime)逻辑说明把文件修改时间作为函数参数传入文件一变参数就变缓存自然失效。这是社区里常用的技巧比手动清除更省心。参数上os.path.getmtime返回浮点数时间戳可哈希适合做缓存键。5.4 中文显示乱码或字体缺失现象图表里的中文显示成方框或者标题里的中文正常但图表里乱码。原因Streamlit 内置图表基于 Altair/Vega默认字体不含中文。Matplotlib 图表则需要手动指定中文字体。解决Matplotlib 需要设置字体Altair 可以通过主题配置。最省事的办法是用st.line_chart等内置图表它们对中文支持较好如果必须用 Matplotlib加上字体设置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # Windows # plt.rcParams[font.sans-serif] [Arial Unicode MS] # macOS plt.rcParams[axes.unicode_minus] False逻辑说明font.sans-serif指定中文字体名称axes.unicode_minus设为 False 解决负号显示为方块的问题。参数上字体名称要写系统里实际安装的Linux 服务器上可能需要额外安装中文字体包。5.5 部署到服务器后外网访问不了现象本地跑得好好的放到云服务器上浏览器访问服务器IP:8501打不开。原因可能是防火墙没放行端口或者 Streamlit 默认只监听 localhost。解决启动时加--server.address 0.0.0.0并确认服务器安全组/防火墙放行了对应端口。另外生产环境不建议直接用 Streamlit 自带的服务器暴露到公网常见做法是前面加一层 Nginx 做反向代理和 HTTPS。# 服务器上启动监听所有网卡 streamlit run app.py --server.address 0.0.0.0 --server.port 8501逻辑说明0.0.0.0表示监听所有网络接口外部请求才能进来。参数上端口要和防火墙放行的端口一致。如果用了 NginxStreamlit 可以只监听127.0.0.1由 Nginx 转发更安全。6. 进阶技巧用 st.session_state 管理跨次运行的交互状态Streamlit 每次重跑脚本都会重置普通变量但st.session_state是个例外——它能在多次运行之间保持状态。这个特性在实现多步表单、购物车、登录态时非常关键。很多新手不知道这个机制写出来的计数器点一下归零就是没用到 session_state。import streamlit as st # 初始化 session_state只在第一次运行时执行 if count not in st.session_state: st.session_state.count 0 # 按钮点击时修改状态 if st.button(点我加一): st.session_state.count 1 st.write(f当前计数{st.session_state.count}) # 多步表单示例 if step not in st.session_state: st.session_state.step 1 if st.session_state.step 1: name st.text_input(输入姓名) if st.button(下一步): st.session_state.name name st.session_state.step 2 elif st.session_state.step 2: st.write(f你好{st.session_state.name}) if st.button(返回): st.session_state.step 1逻辑说明st.session_state是一个类字典对象每个会话独立。用if key not in st.session_state做初始化是标准写法避免每次重跑都覆盖。参数上session_state 的键名不要和 st 控件自动生成的键冲突否则会报DuplicateWidgetID错误。如果冲突给控件加一个唯一的key参数。验证 session_state 是否生效最简单的办法是加一个计数器按钮点几下看数字是否累加。如果归零说明状态没保持住检查初始化逻辑是否写在了条件判断外面。我自己的习惯是凡是需要跨次运行保留的值一律放进 session_state并且初始化代码统一放在脚本最前面用注释标出来。这样后面加功能时不容易漏。另外调试 session_state 时可以用st.write(st.session_state)把整个状态打印出来一目了然。还有一个容易忽略的点st.session_state里的值在浏览器刷新后会丢失因为它存在服务端内存里和浏览器会话绑定。如果你需要持久化得自己接数据库或文件存储。这个边界要清楚别指望它当数据库用。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?