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