Python - Повторное использование функций в обратных вызовах Da sh. - PullRequest
2 голосов
/ 24 февраля 2020

Я пытаюсь создать приложение в среде Python Da sh, которая позволяет пользователю выбрать имя из списка и использовать это имя для заполнения двух других полей ввода. Есть шесть мест, где пользователь может выбрать имя из (того же) списка, и, таким образом, всего 12 обратных вызовов, которые необходимо выполнить. Мой вопрос: как я могу использовать одно определение функции для предоставления нескольких обратных вызовов?

Как я видел в других местах ( здесь, например, ), люди повторно используют одно и то же имя функции при выполнении множественные обратные вызовы, например,

@app.callback(
    Output('rp-mon1-health', 'value'),
    [Input('rp-mon1-name', 'value')]
)
def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['health']
    else:
        return 11

@app.callback(
    Output('rp-mon3-health', 'value'),
    [Input('rp-mon3-name', 'value')]
)
def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['health']
    else:
        return 11

@app.callback(
    Output('rp-mon1-health', 'value'),
    [Input('rp-mon1-name', 'value')]
)
def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['health']
    else:
        return 11

Это тонна идентичных повторений и плохо, если есть исправление, которое мне нужно реализовать позже. В идеале я мог бы сделать что-то вроде:

@app.callback(
    Output('rp-mon1-health', 'value'),
    [Input('rp-mon1-name', 'value')]
)
@app.callback(
    Output('rp-mon2-health', 'value'),
    [Input('rp-mon2-name', 'value')]
)
@app.callback(
    Output('rp-mon3-health', 'value'),
    [Input('rp-mon3-name', 'value')]
)
def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['health']
    else:
        return 11

Однако вышеприведенное заканчивает тем, что не перезвонило первым двум, только последнему. Мой код как есть, ниже.

import json

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

monster_data = json.loads('''[{
    "name": "Ares Mothership",
    "health": 14,
    "transition": 2
  },{
    "name": "Cthugrosh",
    "health": 7,
    "transition": 3
  }]''')
monster_names = [{'label': m['name'], 'value': m['name']} for m in monster_data]
monster_names.append({'label': 'None', 'value': ''})

app = dash.Dash(__name__)


def gen_monster(player, i):
    name = 'Monster #%d:  ' % i
    id_gen = '%s-mon%d' % (player, i)
    output = html.Div([
        html.Label('%s Name   ' % name),
        html.Br(),
        dcc.Dropdown(
            options=monster_names,
            value='',
            id='%s-name' % id_gen
        ),
        html.Br(),
        html.Label('Health'),
        html.Br(),
        dcc.Input(value=11, type='number', id='%s-health' % id_gen),
        html.Br(),
        html.Label('Hyper Transition'),
        html.Br(),
        dcc.Input(value=6, type='number', id='%s-state' % id_gen),
    ], style={'border': 'dotted 1px black'})
    return output


app.layout = html.Div(children=[
    html.H1(children='Monsterpocalypse Streaming Stats Manager'),

    html.Div([
        html.Div([
            html.Label('Left Player Name: '),
            dcc.Input(value='Mark', type='text', id='lp-name'),
            gen_monster('lp', 1),
            html.Br(),
            gen_monster('lp', 2),
            html.Br(),
            gen_monster('lp', 3)
        ], style={'width': '300px'}),

        html.Br(),

        html.Div([
            html.Label('Right Player Name: '),
            dcc.Input(value='Benjamin', type='text'),
            gen_monster('rp', 1),
            html.Br(),
            gen_monster('rp', 2),
            html.Br(),
            gen_monster('rp', 3)
        ], style={'width': '300px'})
    ], style={'columnCount': 2}),

    html.Div(id='dummy1'),
    html.Div(id='dummy2')
])

@app.callback(
    Output('rp-mon1-health', 'value'),
    [Input('rp-mon1-name', 'value')]
)
def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['health']
    else:
        return 11


@app.callback(
    Output('rp-mon1-state', 'value'),
    [Input('rp-mon1-name', 'value')]
)
def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['transition']
    else:
        return 6


if __name__ == '__main__':
    app.run_server(debug=True)

1 Ответ

3 голосов
/ 26 февраля 2020

Вы можете сделать что-то вроде этого:

def update_health(monster):
    if monster != '':
        relevant = [m for m in monster_data if m['name'] == monster]
        return relevant[0]['health']
    else:
        return 11


@app.callback(
    Output('rp-mon1-health', 'value'),
    [Input('rp-mon1-name', 'value')]
)
def monster_1_callback(*args, **kwargs):
    return update_health(*args, **kwargs)

@app.callback(
    Output('rp-mon2-health', 'value'),
    [Input('rp-mon2-name', 'value')]
)
def monster_2_callback(*args, **kwargs):
    return update_health(*args, **kwargs)


@app.callback(
    Output('rp-mon3-health', 'value'),
    [Input('rp-mon3-name', 'value')]
)
def monster_3_callback(*args, **kwargs):
    return update_health(*args, **kwargs)

Теперь функция, содержащая логи c, записывается только один раз, а остальные функции - простые проходы, которые вам не нужно обновлять. .

...