Python 装饰器作为 Dash 中的回调使用作为实例变量的 Dash 对象 - 失败

Posted

技术标签:

【中文标题】Python 装饰器作为 Dash 中的回调使用作为实例变量的 Dash 对象 - 失败【英文标题】:Python Decorator as Callback in Dash Using Dash Object That is an Instance Variable - Fails 【发布时间】:2019-07-10 18:56:46 【问题描述】:

我正在更新一些代码以使用 Dash 和 plotly。绘图的主要代码是在一个类中定义的。我用 Dash 控件替换了一些 Bokeh 小部件,最后得到了一个如下所示的回调:

class MakeStuff:
    def __init__(self, ..., **optional):
        ...
        self.app = dash.Dash(...)
        ...

    @self.app.callback(
    dash.dependencies.Output('indicator-graphic', 'figure'),
        [dash.dependencies.Input('start-time-slider', 'value'),
         dash.dependencies.Input('graph-width-slider', 'value')]
        )
    def update_graphs(self,range_start,graph_width):
        print(...)

我正在关注Dash website 中的一些示例。我能够运行示例,包括回调。在我的代码中,没有装饰器,代码运行没有错误,产生了我期望的图形和控件。 (当然,代码不完整,但没有错误。)当我包含装饰器时,我得到这个错误:

NameError: name 'self' 未定义

我是这样累的,首先,只是模仿代码示例:

class MakeStuff:
    def __init__(self, ..., **optional):
        ...
        app = dash.Dash(...)
        ...

    @app.callback(
    dash.dependencies.Output('indicator-graphic', 'figure'),
    [dash.dependencies.Input('start-time-slider', 'value'),
     dash.dependencies.Input('graph-width-slider', 'value')]
    )
    def update_graphs(self,range_start,graph_width):
        print(...)

当然,变量“app”只能在init函数的范围内知道,所以它不起作用也就不足为奇了,给出类似的错误:

NameError: name 'app' 未定义

是否有一种简单的方法来设置此装饰器以使其工作,同时仍将我的代码保留在类定义中?我猜装饰器正在进行一些预处理,但我不太了解它,无法提出解决方案。

【问题讨论】:

【参考方案1】:

您可以不将回调函数作为装饰器调用,如this answer 所示。这应该在您的 __init__ 函数中起作用:

class MakeStuff:
    def __init__(self, ..., **optional):
        ...
        self.app = dash.Dash(...)
        self.app.callback(
            dash.dependencies.Output('indicator-graphic', 'figure'),
            [dash.dependencies.Input('start-time-slider', 'value'),
             dash.dependencies.Input('graph-width-slider', 'value')]
            )(self.update_graphs)
        ...

    def update_graphs(self,range_start,graph_width):
        print(...)

我以前从未尝试过使用类实例,但看不出有什么理由不工作。

【讨论】:

【参考方案2】:

ned2 提供了一个解决方案here,他使用以下结构在类定义中设置装饰器。

class BaseBlock:
def __init__(self, app=None):
    self.app = app

    if self.app is not None and hasattr(self, 'callbacks'):
        self.callbacks(self.app)

class MyBlock(BaseBlock):
    layout = html.Div('layout for this "block".')

    def callbacks(self, app):

        @app.callback(Output('foo', 'figure'), [Input('bar')])
        def do_things(bar):
            return SOME_DATA

        @app.callback(Output('baz', 'figure'), [Input('boop')])
        def do_things(boop):
            return OTHER_DATA

# creating a new MyBlock will register all callbacks
block = MyBlock(app=app)

# now insert this component into the app's layout 
app.layout['slot'] = block.layout

【讨论】:

以上是关于Python 装饰器作为 Dash 中的回调使用作为实例变量的 Dash 对象 - 失败的主要内容,如果未能解决你的问题,请参考以下文章

如何将时间序列数据中的缩放级别作为 Dash 中的回调输入

Plotly Dash:选择 DataTable 中的行作为回调输出 + 过滤器

python基本知识:函数式编程,装饰器

在 Dash (python) 中,我遇到了滑块和 radioitem 回调的问题

作为基类一部分的 Python 装饰器不能用于装饰继承类中的成员函数

Python中的装饰器的使用及固定模式