在Dash中更灵活地编写回调函数
本文示例代碼已上傳至我的
Github倉庫https://github.com/CNFeffery/dash-master
大家好我是費老師,使用Dash開發過交互式應用的朋友,想必都不會對回調函數感到陌生,作為Dash應用中實現各種交互邏輯的“萬金油”方式,不管是常規的@app.callback(),還是對應瀏覽器端回調的app.clientside_callback()和ClientsideFunction(),其中編排各種回調角色時,我們都是按照先Output,再Input,最后State的順序依次羅列的,且各個角色存在多個時,建議用[]將它們包裹住,以提升代碼可讀性。
但這并不是不可打破的鐵律,事實上,Dash還額外提供了多種多樣的回調角色編排方式,官方稱之為Flexible Callback Signatures,從而解決單個回調函數中角色太多時代碼可讀性變差等問題,今天的文章中,我就將帶大家學習相關的實用知識,從而更清晰地進行Dash應用開發及維護??。
閱讀本文大約需要6分鐘
為了方便演示,我們構造下圖所示的簡單示例Dash應用(完整源碼見文章開頭地址):
如果要編排以兩個按鈕作為示例Input角色,兩個輸入框作為示例State角色,并向兩個文字組件中分別Output不同的參數值內容的回調函數,按照常規的寫法,對應的回調函數可以寫作下方形式:
@app.callback(
[Output('demo-output1', 'children'),
Output('demo-output2', 'children')],
[Input('demo-button1', 'nClicks'),
Input('demo-button2', 'nClicks')],
[State('demo-input1', 'value'),
State('demo-input2', 'value')],
prevent_initial_call=True
)
def demo_callback(nClicks1, nClicks2, value1, value2):
return [
f'nClicks1: {nClicks1}, nClicks2: {nClicks2}',
f'value1: {value1}, value2: {value2}'
]
下面我們以此為基礎,分別介紹其他不同的寫法:
1 字典化角色編排
我們可以用字典來分別編排各類型的角色,其中具體可細分為:
- 僅
Input、State字典化
當僅對回調函數的Input和State角色進行字典化編排時,我們可以通過自定義的鍵值對,完成針對回調函數輸入參數的映射,改造后的示例回調函數如下:
@app.callback(
[Output('demo-output1', 'children'),
Output('demo-output2', 'children')],
inputs=dict(
nClicks1=Input('demo-button1', 'nClicks'),
nClicks2=Input('demo-button2', 'nClicks')
),
state=dict(
value1=State('demo-input1', 'value'),
value2=State('demo-input2', 'value')
),
prevent_initial_call=True
)
def demo_callback(nClicks1, nClicks2, value1, value2):
'''字典化角色編排:僅Input、State字典化'''
return [
f'nClicks1: {nClicks1}, nClicks2: {nClicks2}',
f'value1: {value1}, value2: {value2}'
]
- 全部角色字典化
如果我們將回調函數的Output也進行了字典化改造,那么在回調函數中就需要返回對應鍵值對的字典(返回單個dash.no_update時不受限制),示例寫法如下:
@app.callback(
output=dict(
content1=Output('demo-output1', 'children'),
content2=Output('demo-output2', 'children')
),
inputs=dict(
nClicks1=Input('demo-button1', 'nClicks'),
nClicks2=Input('demo-button2', 'nClicks')
),
state=dict(
value1=State('demo-input1', 'value'),
value2=State('demo-input2', 'value')
),
prevent_initial_call=True
)
def demo_callback(nClicks1, nClicks2, value1, value2):
'''字典化角色編排:全部角色字典化'''
return dict(
content1=f'nClicks1: {nClicks1}, nClicks2: {nClicks2}',
content2=f'value1: {value1}, value2: {value2}'
)
通過字典化角色的形式,我們可以為每個角色*起名字,建議是起跟功能相關的名字,如login_button_click,或登錄按鈕點擊這樣的中文鍵名,只要能幫助你更好地讀懂回調函數邏輯就可以??。
2 嵌套式字典化角色編排
當我們在使用上文所介紹的字典化角色編排方式時,除了在字典中平鋪書寫相應角色外,還可以向下繼續進行字典嵌套,從而實現更*的參數分組效果,相應的,對應輸入參數也會以字典的形式傳入內部的各鍵值對參數:
@app.callback(
output=dict(
content1=Output('demo-output1', 'children'),
content2=Output('demo-output2', 'children')
),
inputs=dict(
nClicks1=Input('demo-button1', 'nClicks'),
nClicks2=Input('demo-button2', 'nClicks')
),
state=dict(
input_values=dict(
value1=State('demo-input1', 'value'),
value2=State('demo-input2', 'value')
)
),
prevent_initial_call=True
)
def demo_callback(nClicks1, nClicks2, input_values):
'''嵌套式字典化角色編排'''
return dict(
content1=f'nClicks1: {nClicks1}, nClicks2: {nClicks2}',
content2='value1: {value1}, value2: {value2}'.format(**input_values)
)
3 對需要返回若干dash.no_update的情況進行簡化
針對字典化角色編排Output的方式,當我們僅需要對部分輸出目標返回實際值,對其余目標返回dash.no_update時,可以配合標準庫collections中的defaultdict以及dash回調的上下文簡化相關過程:
@app.callback(
output=dict(
content1=Output('demo-output1', 'children'),
content2=Output('demo-output2', 'children')
),
inputs=dict(
nClicks1=Input('demo-button1', 'nClicks'),
nClicks2=Input('demo-button2', 'nClicks')
),
state=dict(
value1=State('demo-input1', 'value'),
value2=State('demo-input2', 'value')
),
prevent_initial_call=True
)
def demo_callback(nClicks1, nClicks2, value1, value2):
'''字典化Output配合defaultdict'''
# 假設我們需要除了content1之外的其他角色默認輸出為dash.no_update
output = defaultdict(
lambda: dash.no_update,
dict(
content1=f'nClicks1: {nClicks1}, nClicks2: {nClicks2}'
)
)
return {
key: output[key]
# 通過上下文遍歷所有Output字典鍵名
for key in dash.ctx.outputs_grouping.keys()
}
其中構造defaultdict并設置默認值等過程,我也會在fac即將發布的0.3.x版本中封裝為一步到位的工具函數,畢竟這種場景在進階Dash應用的開發中還是很常用的,省得在常規方式中逐個寫dash.no_update或其他默認值。
除此之外,有關Flexible Callback Signatures還有一些其他的寫法,但是在我看來并沒有字典化寫法這么實用,感興趣的朋友可以移步https://dash.plotly.com/flexible-callback-signatures了解更多。
以上就是本文的全部內容,更多有關dash應用開發的前沿知識和技巧歡迎持續關注玩轉dash公眾號。
總結
以上是生活随笔為你收集整理的在Dash中更灵活地编写回调函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于JuiceFS 的低成本 Elast
- 下一篇: 【scipy 基础】--正交距离回归