本文示例代碼已上傳至我的
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公衆號。