Python+Dash快速web应用开发:回调交互篇(上)

简介: Python+Dash快速web应用开发:回调交互篇(上)

1 简介

这是我的系列教程「Python+Dash快速web应用开发」的第三期,在前两期的教程中,我们围绕什么是Dash,以及如何配合方便好用的第三方拓展dash-bootstrap-components来为我们的Dash应用设计布局展开了非常详细的介绍。

Dash最吸引我的地方在于其高度封装了react.js,使得我们无需编写js语句,纯Python编程就可以实现浏览器前端与后端计算之间常规的异步通信,从而创造出功能强大的交互式web应用。

图1

从今天的文章开始,我就将开始带大家走进Dash的核心内容——「回调」

2 Dash中的基础回调

2.1 最基础的回调

Dash中的「回调」callback)是以装饰器的形式,配合自编回调函数,实现前后端异步通信交互,这句话可能不太好理解,我们从一个简单的例子出发来认识Dash中的「回调」

app1.py

import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(
    __name__,
    external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
    [
        html.Br(),
        html.Br(),
        html.Br(),
        dbc.Container(
            [
                dbc.Row(
                    [
                        dbc.Col(dbc.Input(id='input-value',
                                          placeholder='请输入些东西'),
                                width=12),
                        dbc.Col(dbc.Label(id='output-value'),
                                width=12)
                    ]
                )
            ]
        )
    ]
)
# 对应app实例的回调函数装饰器
@app.callback(
    Output('output-value', 'children'),
    Input('input-value', 'value')
)
def input_to_output(input_value):
    '''
    简单的回调函数
    '''
    return input_value
if __name__ == '__main__':
    app.run_server()

先来看看app1的交互效果:

图2

下面我们来分解上面的代码,梳理一下要构造一个具有实际交互功能的Dash应用需要做什么:

  • 「确定输入与输出部件」

一个可交互的系统一定是有「输入」「输出」的,我们开头导入的InputOutput对象,他们分别扮演着「输入者」「输出者」两种角色,其各自的第一个参数component_id用于联动前端部分定义的部件。

我们在前面定义前端部件时,为dbc.Input对应的输入框设置了id='input-value',为dbc.Label对应的文字输出设置了id='output-value',让它们作为第一个参数可以被Input()Output()唯一识别出来。

  • 「确定输入与输出内容」

在确定了「输入者」「输出者」之后,更重要的是为告诉Dash需要监听什么输入,响应什么输出,这就要用到第二个参数component_property

它与对应的前端部件有关,譬如我们的dbc.Input()输入框,其被输入的内容都存在value属性中,而children属性是dbc.Label以及绝大多数html部件的第一个参数,这样我们就确定了输入输出内容。

  • 「装饰回调函数」

app.callback()装饰器按照规定的先Output()Input()的顺序传入相应对象,而既然是装饰器,自然需要配合自定义回调函数使用。

我们的input_to_output()就是对应的回调函数,其参数与装饰器中的Input()对应,而函数内部则用来定义计算处理过程。

最后return的对象则对应Output()

# 对应app实例的回调函数装饰器
@app.callback(
    Output('output-value', 'children'),
    Input('input-value', 'value')
)
def input_to_output(input_value):
    '''
    简单的回调函数
    '''
    return input_value

通过上面这样的结构,我们得以纯Python“寥寥数语”实现了交互功能,赋予我们编写任意功能Dash应用的能力。

2.2 同时设置多个Input()与Output()

在上一小节中我们介绍的是最基本的「单输入 -> 单输出」回调模式,很多时候我们需要更复杂的回调模式,譬如下面的例子:

app2.py

import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(
    __name__,
    external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
    [
        html.Br(),
        html.Br(),
        html.Br(),
        dbc.Container(
            [
                dbc.Row(
                    [
                        dbc.Col(dbc.Input(id='input-value1'), width=3),
                        dbc.Col(html.P('+'), width=1),
                        dbc.Col(dbc.Input(id='input-value2'), width=3),
                    ],
                    justify='start'
                ),
                html.Hr(),
                dbc.Label(id='output-value')
            ]
        )
    ]
)
@app.callback(
    Output('output-value', 'children'),
    Input('input-value1', 'value'),
    Input('input-value2', 'value')
)
def input_to_output(input_value1, input_value2):
    try:
        return float(input_value1) + float(input_value2)
    except:
        return '请输入合法参数!'
if __name__ == '__main__':
    app.run_server()

图3

这里我们的Input()对象不止一个,在Output()对象之后依次传入(也可以把所有Input()对象包在一个列表中传入),其顺序对应后面回调函数的参数顺序,从而实现了多个输入值的一一对应。

同样的,Output()也可以有多个:

app3.py

import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = dash.Dash(
    __name__,
    external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
    [
        html.Br(),
        html.Br(),
        html.Br(),
        dbc.Container(
            [
                dbc.Row(
                    [
                        dbc.Col(dbc.Input(id='input-lastname'), width=3),
                        dbc.Col(html.P('+'), width=1),
                        dbc.Col(dbc.Input(id='input-firstname'), width=3),
                    ],
                    justify='start'
                ),
                html.Hr(),
                dbc.Label(id='output1'),
                html.Br(),
                dbc.Label(id='output2')
            ]
        )
    ]
)
@app.callback(
    [Output('output1', 'children'),
     Output('output2', 'children')],
    [Input('input-lastname', 'value'),
     Input('input-firstname', 'value')]
)
def input_to_output(lastname, firstname):
    try:
        return '完整姓名:' + lastname + firstname, f'姓名长度为{len(lastname+firstname)}'
    except:
        return '等待输入...', '等待输入...'
if __name__ == '__main__':
    app.run_server()

图4

可以看到不管是多个Output()还是Input(),只需要嵌套在列表中即可。

2.3 利用State()实现惰性交互

很多情况下,如果我们的回调函数计算过程时间开销较大,那么像前面介绍的仅靠Input()Output()实现的前后端通信会很频繁,因为监听到的所有输入部件对应属性值只要略一改变,就会触发回调。

为了解决这类问题,Dash中设计了State()对象,我们可以利用State()替换Input()来绑定对应的输入值,再将一些需要主动触发的譬如dbc.Button()按钮部件的属性n_clicks,作为Input()对象进行绑定。

让我们通过下面的例子更好的理解它的作用:

app4.py

import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
app = dash.Dash(
    __name__,
    external_stylesheets=['css/bootstrap.min.css']
)
app.layout = html.Div(
    [
        html.Br(),
        html.Br(),
        html.Br(),
        dbc.Container(
            [
                dbc.Row(
                    [
                        dbc.Col(dbc.Input(id='input-value'),
                                width=4),
                        dbc.Col(dbc.Button('小写转大写',
                                           id='state-button',
                                           n_clicks=0),
                                width=4),
                        dbc.Col(dbc.Label(id='output-value',
                                          style={'padding': '0',
                                                 'margin': '0',
                                                  'line-height': '38px'}),
                                width=4)
                    ],
                    justify='start'
                )
            ]
        )
    ]
)
@app.callback(
    Output('output-value', 'children'),
    Input('state-button', 'n_clicks'),
    State('input-value', 'value')
)
def input_to_output(n_clicks, value):
    if n_clicks:
        return value.upper()
if __name__ == '__main__':
    app.run_server()

图5

可以看到,装饰器中按照Output()Input()State()的顺序传入各个对象后,我们的Button()部件的n_clicks参数记录了对应的按钮被点击了多少次,初始化我们设置其为0,之后每次等我们输入完单词,主动去点击按钮从而增加其被点击次数记录时,回调函数才会被触发,这样就方便了我们的很多复杂应用场景~

目录
相关文章
|
9月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
645 4
|
11月前
|
供应链 新能源 调度
微电网调度(风、光、储能、电网交互)(Matlab&Python代码实现)
微电网调度(风、光、储能、电网交互)(Matlab&Python代码实现)
244 0
|
11月前
|
存储 监控 算法
淘宝买家秀 API开发实录Python(2025)
本文讲述了作者在电商开发领域,尤其是对接淘宝买家秀 API 接口过程中所经历的挑战与收获。从申请接入、签名验证、频率限制到数据处理和实时监控,作者分享了多个实战经验与代码示例,帮助开发者更高效地获取和处理买家秀数据,提升开发效率。
|
10月前
|
设计模式 人工智能 API
AI智能体开发实战:17种核心架构模式详解与Python代码实现
本文系统解析17种智能体架构设计模式,涵盖多智能体协作、思维树、反思优化与工具调用等核心范式,结合LangChain与LangGraph实现代码工作流,并通过真实案例验证效果,助力构建高效AI系统。
1070 7
|
数据采集 存储 数据库
Python爬虫开发:Cookie池与定期清除的代码实现
Python爬虫开发:Cookie池与定期清除的代码实现
|
11月前
|
算法 程序员 API
电商程序猿开发实录:淘宝商品python(2)
本文分享了开发者在对接淘宝商品详情API过程中的真实经历,涵盖权限申请、签名验证、限流控制、数据解析及消息订阅等关键环节,提供了实用的Python代码示例,帮助开发者高效调用API,提升系统稳定性与数据处理能力。
|
存储 算法 数据可视化
用Python开发猜数字游戏:从零开始的手把手教程
猜数字游戏是编程入门经典项目,涵盖变量、循环、条件判断等核心概念。玩家通过输入猜测电脑生成的随机数,程序给出提示直至猜中。项目从基础实现到功能扩展,逐步提升难度,适合各阶段Python学习者。
1021 0
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!
|
JavaScript 前端开发 API
鸿蒙5开发宝藏案例分享---Web加载时延优化解析
本文深入解析了鸿蒙开发中Web加载完成时延的优化技巧,结合官方案例与实际代码,助你提升性能。核心内容包括:使用DevEco Profiler和DevTools定位瓶颈、四大优化方向(资源合并、接口预取、图片懒加载、任务拆解)及高频手段总结。同时提供性能优化黄金准则,如首屏资源控制在300KB内、关键接口响应≤200ms等,帮助开发者实现丝般流畅体验。
|
前端开发 JavaScript Shell
鸿蒙5开发宝藏案例分享---Web页面内点击响应时延分析
本文为鸿蒙开发者整理了Web性能优化的实战案例解析,结合官方文档深度扩展。内容涵盖点击响应时延核心指标(≤100ms)、性能分析工具链(如DevTools时间线、ArkUI Trace抓取)以及高频优化场景,包括递归函数优化、网络请求阻塞解决方案和setTimeout滥用问题等。同时提供进阶技巧,如首帧加速、透明动画陷阱规避及Web组件初始化加速,并通过优化前后Trace对比展示成果。最后总结了快速定位问题的方法与开发建议,助力开发者提升Web应用性能。

推荐镜像

更多