You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python Shiny中仅执行一次函数并展示其两个输出?

问题:Python Shiny中仅执行一次高计算量函数,多卡片复用输出

我有一个遍历数据并生成两个输出的函数(示例中的check()函数),希望将这两个输出分别展示在不同的卡片中。当前实现中check()函数会被执行两次,处理真实数据时因高计算量导致效率极低。请问是否有办法在Python Shiny中仅运行该函数一次,却仍能在不同卡片中使用其两个输出?

最小可复现示例(MRE)

from shiny import App, render, ui, reactive
from pathlib import Path


app_ui = ui.page_fillable(
    ui.layout_sidebar(
        ui.sidebar(
            ui.input_text("numbers", "Number you want to check", value="1,2,3,4,5,6,7,8"),
            ui.input_action_button("check_numbers", "Check your numbers")
        ),
        ui.output_ui("numbers_frames")
    )
)


def server(input, output, session):

    @render.ui
    @reactive.event(input.check_numbers)
    def numbers_frames():

        return ui.TagList(
                    ui.layout_columns(
                        ui.card(
                            ui.card_header("even"),
                            ui.output_text("even"),
                        ),
                        ui.card(
                            ui.card_header("odd"),
                            ui.output_text("odd"),
                        ),
                    )
                )

    @reactive.event(input.check_numbers)
    def check():

        even = []
        odd = []

        for number in input.numbers().split(','):
            number_int = int(number.strip())
            if number_int % 2 == 0:
                even.append(str(number_int))
            else:
                odd.append(str(number_int))

        print("check() has been exectuted")

        return (even, odd)


    @output
    @render.text
    def even():

        even_output = check()[0]

        return ','.join(even_output)

    @output
    @render.text
    def odd():

        odd_output = check()[1]

        return ','.join(odd_output)


src_dir = Path(__file__).parent / "src"
app = App(app_ui, server, static_assets=src_dir)

解决方案

方法1:使用@reactive.cached缓存函数结果

给check()函数添加@reactive.cached装饰器,函数结果会被缓存,多次调用时不会重复执行计算,仅在触发事件(点击按钮)时重新计算一次。

修改后的核心代码:

@reactive.cached
    @reactive.event(input.check_numbers)
    def check():
        even = []
        odd = []
        for number in input.numbers().split(','):
            number_int = int(number.strip())
            if number_int % 2 == 0:
                even.append(str(number_int))
            else:
                odd.append(str(number_int))
        print("check() has been executed")
        return (even, odd)

    @output
    @render.text
    def even():
        return ','.join(check()[0])

    @output
    @render.text
    def odd():
        return ','.join(check()[1])

方法2:使用reactive.Value存储计算结果

通过reactive.Value保存check()的执行结果,按钮点击时触发计算并更新这个值,两个输出组件直接读取缓存的值,避免重复调用函数。

修改后的核心代码:

def server(input, output, session):
    # 初始化reactive.Value存储结果
    check_result = reactive.Value(tuple())

    @render.ui
    @reactive.event(input.check_numbers)
    def numbers_frames():
        return ui.TagList(
                    ui.layout_columns(
                        ui.card(
                            ui.card_header("even"),
                            ui.output_text("even"),
                        ),
                        ui.card(
                            ui.card_header("odd"),
                            ui.output_text("odd"),
                        ),
                    )
                )

    # 按钮点击时执行计算并更新缓存
    @reactive.Effect
    @reactive.event(input.check_numbers)
    def _run_check():
        even = []
        odd = []
        for number in input.numbers().split(','):
            number_int = int(number.strip())
            if number_int % 2 == 0:
                even.append(str(number_int))
            else:
                odd.append(str(number_int))
        print("check() has been executed")
        check_result.set((even, odd))

    @output
    @render.text
    def even():
        return ','.join(check_result()[0])

    @output
    @render.text
    def odd():
        return ','.join(check_result()[1])

两种方法都能实现仅执行一次计算逻辑,然后在不同卡片中复用输出结果,解决高计算量场景下的效率问题。

内容的提问来源于stack exchange,提问作者gernophil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:01:01