入门 Eva J Patel(freeCodeCamp) 2026-09-10 16:14:02 · 0 阅读

第8章 处理多个输入与输出

随着应用功能越来越丰富,往往需要不止一个输入。

计算器需要两个数字,文本生成应用可能同时要提示词、风格、长度和语言。

机器学习应用可能需要一张图片和一个置信度阈值,文档分析应用则可能需要一个文件加一个问题。

只要理解了组件与函数之间如何传递值,Gradio 就能自然地应对这些场景。

多个函数参数

从一个 Python 函数开始:

def calculate_rectangle(length, width):
    area = length * width
    perimeter = 2 * (length + width)

    return area, perimeter

两个输入,两个输出。

直接这样表示:

import gradio as gr

def calculate_rectangle(length, width):
    area = length * width
    perimeter = 2 * (length + width)

    return area, perimeter

with gr.Blocks() as demo:
    length = gr.Number(label="Length")
    width = gr.Number(label="Width")

    area = gr.Number(label="Area")
    perimeter = gr.Number(label="Perimeter")

    button = gr.Button("Calculate")

    button.click(
        fn=calculate_rectangle,
        inputs=[length, width],
        outputs=[area, perimeter]
    )

demo.launch()

对应关系很直观:

length → first function parameter
width → second function parameter

输出同理:

area → first returned value
perimeter → second returned value

顺序的重要性

假设你的函数是:

def calculate(length, width):
    ...

而你又写了:

inputs=[width, length]

函数会按你列出的顺序接收值,不会自动纠正。

Gradio 并不关心你本意是让第一个组件叫 "length",它只是按配置好的顺序传递。

所以给变量起个清晰的名称很重要。

不同类型的多个输入

组件不必是同一种类型。

比如:

def generate_profile(name, age, interests):
    return (
        f"{name} is {age} years old. "
        f"Their interests include: {', '.join(interests)}."
    )

可以这样定义组件:

name = gr.Textbox()
age = gr.Number()
interests = gr.CheckboxGroup(
    choices=["AI", "Web Development", "Design", "Data Science"]
)

然后:

button.click(
    fn=generate_profile,
    inputs=[name, age, interests],
    outputs=output
)

这是实际应用中非常常见的模式。

返回不同类型

一个函数可以返回不同类型的数据。

例如:

def analyze_number(number):
    doubled = number * 2
    description = f"The number {number} was doubled."

    return doubled, description

然后:

number_output = gr.Number()
text_output = gr.Textbox()

再写:

button.click(
    fn=analyze_number,
    inputs=number,
    outputs=[number_output, text_output]
)

第一个输出是数值,第二个是文本。

返回结构化信息

假设你要分析一个人的信息:

def analyze_person(name, age):
    category = "adult" if age >= 18 else "minor"

    return {
        "name": name,
        "age": age,
        "category": category
    }

可以使用:

result = gr.JSON()

当应用包含多个相关字段时,这种方式很有用。

返回表格

假设用户上传了信息,而你的 Python 函数会生成一个表格:

def generate_scores():
    return [
        ["Alice", 95],
        ["Bob", 88],
        ["Charlie", 91]
    ]

然后:

table = gr.Dataframe(
    headers=["Student", "Score"]
)

函数返回的数据就能填充到表格中。

输出不必同时显示

有时你的应用会有不同的模式。

例如,下拉框可以列出多个选项供用户选择:

Summary
Detailed Analysis
Raw Data

应用会根据用户的选择更新对应的输出。

动态组件的行为在此发挥了作用。

可选值与空输入

真实用户不会每次都填完所有字段。

假设:

def create_greeting(first_name, last_name):
    return f"Hello, {first_name} {last_name}!"

如果 last_name 为空,输出结果可能会显得不自然。

可以这样处理:

def create_greeting(first_name, last_name):
    first_name = first_name.strip()
    last_name = last_name.strip()

    if last_name:
        return f"Hello, {first_name} {last_name}!"

    return f"Hello, {first_name}!"

这也提醒我们:界面设计与 Python 校验是配合工作的。

设计表单

下面来创建一个小应用,用于收集一本书的相关信息。

import gradio as gr

def create_book_summary(title, author, genre, rating):
    return (
        f"Title: {title}\n"
        f"Author: {author}\n"
        f"Genre: {genre}\n"
        f"Rating: {rating}/10"
    )

with gr.Blocks() as demo:
    title = gr.Textbox(label="Book Title")
    author = gr.Textbox(label="Author")

    genre = gr.Dropdown(
        choices=[
            "Fiction",
            "Science Fiction",
            "Fantasy",
            "Mystery",
            "Non-fiction"
        ],
        label="Genre"
    )

    rating = gr.Slider(
        minimum=1,
        maximum=10,
        value=5,
        step=1,
        label="Rating"
    )

    submit = gr.Button("Create Summary")

    output = gr.Textbox(
        label="Book Summary",
        lines=6
    )

    submit.click(
        fn=create_book_summary,
        inputs=[title, author, genre, rating],
        outputs=output
    )

demo.launch()

注意每种输入组件承担不同的功能。

表单越长,越不希望界面变成一长列到底。后面我们会用行、列、分组和标签页来组织组件。

目前你只需要理解一个核心概念:多输入本质上就是传给事件的组件列表。

一次操作产生多个输出

以一个图像分析应用为例。

它可能输出:

  • 预测类别,

  • 置信度评分,

  • 描述文本,

  • 以及处理后的图像。

对应的 Python 函数可以返回四个值:

def analyze_image(image):
    label = "cat"
    confidence = 0.94
    description = "The image appears to contain a cat."
    processed = image

    return label, confidence, description, processed

界面可以包含:

label = gr.Textbox()
confidence = gr.Number()
description = gr.Textbox()
processed = gr.Image()

然后:

button.click(
    fn=analyze_image,
    inputs=image,
    outputs=[
        label,
        confidence,
        description,
        processed
    ]
)

这样,用户只需一次操作,整个结果区域就会同步更新。

返回 None

有时函数并不需要更新所有输出。

在合适的场景下,你可以对某个输出返回 None,根据你设计的交互行为,保留其原值或将其清空。

例如:

def process(value):
    if not value:
        return "Please enter a value.", None

    return "Success", value

设计多输出函数时,要明确每个返回值的具体含义。

Interface 中使用多输入

同样的思路也适用于 gr.Interface

例如:

import gradio as gr

def calculate(a, b):
    return a + b, a * b

demo = gr.Interface(
    fn=calculate,
    inputs=[
        gr.Number(label="First Number"),
        gr.Number(label="Second Number")
    ],
    outputs=[
        gr.Number(label="Sum"),
        gr.Number(label="Product")
    ]
)

demo.launch()

因此,Interface 同样支持多路输入和输出。

什么时候从 Interface 迁移到 Blocks

如果你只需要:

inputs → function → outputs

那用 Interface 就够了。

但如果需要:

  • 多个按钮

  • 自定义事件关系

  • 复杂布局

  • 动态更新

  • 标签页

  • 状态管理

  • 多个独立的工作流

Blocks 通常能给你更强的控制力。

一个更贴近实际的例子

我们来搭一个简单的 AI 写作配置界面。

用户输入主题、语气、篇幅、是否包含示例,以及语言。

import gradio as gr

def generate_article(
    topic,
    tone,
    length,
    include_examples,
    language
):
    examples = "Include practical examples." if include_examples else "Do not include examples."

    return (
        f"Topic: {topic}\n"
        f"Tone: {tone}\n"
        f"Length: {length}\n"
        f"Language: {language}\n"
        f"{examples}"
    )

with gr.Blocks() as demo:
    topic = gr.Textbox(
        label="Topic",
        lines=4
    )

    tone = gr.Dropdown(
        choices=["Professional", "Friendly", "Academic", "Casual"],
        label="Tone"
    )

    length = gr.Slider(
        minimum=100,
        maximum=5000,
        value=1000,
        step=100,
        label="Approximate Length"
    )

    include_examples = gr.Checkbox(
        label="Include practical examples"
    )

    language = gr.Dropdown(
        choices=["English", "Spanish", "French", "German"],
        label="Language"
    )

    button = gr.Button("Generate")

    output = gr.Textbox(
        label="Configuration"
    )

    button.click(
        fn=generate_article,
        inputs=[
            topic,
            tone,
            length,
            include_examples,
            language
        ],
        outputs=output
    )

demo.launch()

这个例子还没有真正生成文章,但这是有意为之。

我们先掌握界面的搭建模式,理解之后,再把函数换成真正的 AI 模型就容易多了。

避免写巨型函数

当应用有十个输入时,很容易就想写一个巨大的函数,把所有逻辑全塞进去。

但这并不总是好选择。

更好的做法是把职责拆分开:

def validate_inputs(...):
    ...


def build_prompt(...):
    ...


def call_model(...):
    ...


def format_result(...):
    ...

再用一个轻量的编排函数把各步串起来:

def generate(...):
    validate_inputs(...)
    prompt = build_prompt(...)
    result = call_model(prompt)

    return format_result(result)

这样 Gradio 事件处理器就清晰可控了。

动手试试

搭建一个"旅行规划器"界面。

让用户输入:

  • 目的地

  • 天数

  • 预算

  • 旅行风格

  • 兴趣偏好

返回至少三个输出:

  • 简短的行程摘要

  • 每日预算估算

  • 推荐活动

暂时不用调用 AI 模型,用普通 Python 逻辑实现即可。

重点在于练习管理多个输入和输出。

要点总结

  • 函数可以接收多个输入。

  • 事件可以把多个组件连到同一个函数上。

  • 函数可以返回多个输出。

  • 输出的顺序必须与返回值顺序一致。

  • 输入可以是完全不同的组件类型。

  • 结构化结果可以用 JSONDataframe 等组件展示。

  • 复杂应用将界面代码与业务逻辑分离,更易维护。

评论 (0)