Python Panel中template.serveable异常:下拉框切换页面不更新且端口占用
问题
本地存储4个CSV文件,每个对应店铺详情,包含ItemNumber、ItemName、ItemBrand、ItemCost字段。使用Python Panel将CSV转为交互式数据框在浏览器展示,程序启动后浏览器可正常打开,但切换下拉框选择不同文件时,页面内容不更新,且报错:
2023-06-16 23:38:24,500 ERROR: panel.reactive - Callback failed for object named "Select File Name" changing property {'value': 'File2'} . OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
已尝试在切换下拉框时停止旧服务并启动新服务避免端口冲突,但未生效。使用template.show()会随机端口启动新服务,但需要固定端口展示不同下拉框对应的内容。原代码如下:
#!/usr/bin/env python3 import pandas as pd from pathlib import Path import panel as pn import hvplot.pandas fileName = "File1" df_file_name = fileName + "_df.csv" df_filepath = Path('C:\\Users\\user1\\MyPythonApp\\' + df_file_name) serveable = None def dfToDisplay(file): global serveable # Access the 'serveable' variable # Stop the previous 'servable' if it exists if serveable is not None: serveable.stop() time.sleep(10) if type(file) == str: filenm = file else: filenm = file[-2] df_path = Path("C:\\Users\\user1\\MyPythonApp\\" + filenm + "_df.csv") displayDF = pd.read_csv(df_path) interactivedf = displayDF.interactive() itable = interactivedf.pipe(pn.widgets.Tabulator, pagination='local', page_size=50, layout='fit_data', theme='default', disabled=True, widths={'index': '70', 'ItemNumber': '130', 'ItemName': '200', 'ItemBrand': '150', 'ItemCost': '900'}) template = pn.template.FastListTemplate(title='Blah blah Details', sidebar=['Filename', dropdown], logo='https://abccorp.com/logo.svg', main=[itable.panel()]) serveable = pn.serve(template, port=20001, show=False) dropdown = pn.widgets.Select(name='Select File Name', options=['File1', 'File2', 'File3', 'File4']) dropdown.param.watch(dfToDisplay, 'value') dfToDisplay(fileName)
解决方案
核心问题是错误地在回调里重复启动pn.serve服务,Panel的正确做法是只启动一次服务,通过更新组件内容实现页面刷新,而非重启服务。修复后的代码如下:
#!/usr/bin/env python3 import pandas as pd from pathlib import Path import panel as pn import hvplot.pandas # 初始化Tabulator组件所需的Panel扩展 pn.extension('tabulator') # 定义文件基础路径 BASE_PATH = Path('C:\\Users\\user1\\MyPythonApp\\') # 创建下拉选择组件 dropdown = pn.widgets.Select(name='Select File Name', options=['File1', 'File2', 'File3', 'File4']) # 初始化Tabulator表格组件,配置固定参数 itable = pn.widgets.Tabulator( pagination='local', page_size=50, layout='fit_data', theme='default', disabled=True, widths={'index': '70', 'ItemNumber': '130', 'ItemName': '200', 'ItemBrand': '150', 'ItemCost': '900'} ) # 定义表格数据更新函数 def update_table(file_name): # 拼接目标文件路径 df_path = BASE_PATH / f"{file_name}_df.csv" # 读取CSV数据 displayDF = pd.read_csv(df_path) # 更新表格组件的数据内容 itable.value = displayDF # 绑定下拉框选择事件到更新函数 dropdown.param.watch(lambda event: update_table(event.new), 'value') # 初始化加载第一个文件的数据 update_table('File1') # 创建页面模板并挂载组件 template = pn.template.FastListTemplate( title='Blah blah Details', sidebar=['Filename', dropdown], logo='https://abccorp.com/logo.svg', main=[itable] ) # 仅启动一次服务,固定端口20001 pn.serve(template, port=20001, show=True)
关键修改说明:
- 移除重复服务启动逻辑:只在程序末尾启动一次
pn.serve,彻底避免端口冲突问题。 - 组件内容更新替代服务重启:通过修改
Tabulator的value属性刷新表格数据,这是Panel原生的交互更新方式,无需重启服务。 - 简化回调逻辑:直接通过
event.new获取下拉框选中的文件名,省去复杂的参数类型判断。 - 规范路径处理:使用
Path对象的/操作符拼接路径,避免字符串拼接的潜在错误。 - 初始化组件扩展:添加
pn.extension('tabulator')确保Tabulator组件正常渲染。
内容的提问来源于stack exchange,提问作者Thushar Mohan
相关产品推荐
相关产品推荐

