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

GUI函数组合开发:用户自定义参数缺失处理方案问询

问题描述

我正在开发一款允许用户通过“组合”现有函数创建自定义函数的GUI应用,拟实现类似Scratch的拖拽式交互:用户可从列表拖拽函数、为自定义函数命名并定义后续可传入的参数。

为演示功能,我编写了包含Sync和SupC两个函数的简化代码,可通过FunctionNode组合函数。当前代码支持以编程方式配置函数及其参数,例如创建组合Sync与SupC的foo函数:

def Sync(*args):
    text = ''
    for automato in args:
        text += automato.name + ' + ' 
    return text.rstrip(' + ')

def SupC(text1:Automaton, text2:Automaton):
    result = ''
    for letter in text1.name:
        if letter not in text2.name:
            result += letter
    return result
    
def foo(sync1, sync2):
    return SupC(Sync(sync1), Sync(sync2))

但由于是GUI实现,用户无需接触Python代码,目前我的实现如下:

from inspect import signature

class FunctionNode:
    def __init__(self, func, name=None, args=None):
        if name is None:
            self.name = func.__name__
        else:
            self.name = name
        self.func = func
        self.args = args if args else []
        self.func_arguments = {param: None for param in signature(func).parameters}
        self.user_parameters = dict()

    def __str__(self):
        return f'{self.name}(func_arguments={self.func_arguments}, user_parameters={self.user_parameters})'

    def pass_argument(self, arg, value):
        if arg not in self.func_arguments:
            raise ValueError(f'Function {self.func.__name__} does not have argument {arg}')
        if callable(value):
            self.func_arguments[arg] = FunctionNode(value)
        elif isinstance(value, str):
            self.func_arguments[arg] = None
            self.user_parameters[arg] = value
        else:
            self.func_arguments[arg] = value

    def set_function_name(self, name):
        self.name = name


class Automaton:
    def __init__(self, name=None):
        self.name = name
        

def Sync(*args):
    text = ''
    for automato in args:
        text += automato.name + ' + ' 
    return text.rstrip(' + ')

def SupC(text1:Automaton, text2:Automaton):
    result = ''
    for letter in text1.name:
        if letter not in text2.name:
            result += letter
    return result

node = FunctionNode(SupC, name='foo')
node.pass_argument('text1', Sync)
node.pass_argument('text2', Sync)
node.func_arguments['text1'].pass_argument('args', Sync)
node.func_arguments['text2'].pass_argument('args', Sync)
node.func_arguments['text1'].func_arguments['args'].pass_argument('args', 'sync1')
node.func_arguments['text2'].func_arguments['args'].pass_argument('args', 'sync2')

def execute(node):
    for value in node.func_arguments.values():
        if value:
            print(value)
            return execute(value)
        else:
            print(node.user_parameters)

execute(node)

当前代码可在无缺失参数时执行函数,但无法实现接收用户任意参数的功能,请问该如何处理用户指定参数尚未提供的情况?


解决方案

1. 标记待输入的用户参数

在FunctionNode中新增字段区分已绑定参数和待用户输入的参数,约定以$开头的字符串作为用户参数占位符,同时用集合记录待输入参数名:

from inspect import signature

class FunctionNode:
    def __init__(self, func, name=None, args=None):
        if name is None:
            self.name = func.__name__
        else:
            self.name = name
        self.func = func
        self.args = args if args else []
        self.func_arguments = {param: None for param in signature(func).parameters}
        self.user_parameters = dict()
        self.pending_user_params = set()  # 新增:记录需用户输入的参数

    def pass_argument(self, arg, value):
        if arg not in self.func_arguments:
            raise ValueError(f'Function {self.func.__name__} does not have argument {arg}')
        if callable(value):
            self.func_arguments[arg] = FunctionNode(value)
            self.pending_user_params.discard(arg)  # 绑定函数后移除待输入标记
        elif isinstance(value, str) and value.startswith('$'):
            self.func_arguments[arg] = None
            self.pending_user_params.add(arg)  # 标记为待输入
            self.user_parameters[arg] = value  # 保存占位符(如$sync1)
        else:
            self.func_arguments[arg] = value
            self.pending_user_params.discard(arg)

    # 保留原有__str__、set_function_name方法

2. 递归检查参数完整性

新增validate方法,递归遍历整个函数节点树,收集所有待输入的参数:

class FunctionNode:
    # 其他方法...
    def validate(self):
        pending = set(self.pending_user_params)
        # 递归检查子节点
        for child_node in self.func_arguments.values():
            if isinstance(child_node, FunctionNode):
                pending.update(child_node.validate())
        return pending

使用时先检查参数是否齐全:

pending = node.validate()
if pending:
    print(f"请补充以下参数:{', '.join(pending)}")
else:
    # 执行函数逻辑

3. 执行时注入用户参数

修改execute函数,接收用户输入的参数字典,将占位符替换为实际值并递归执行:

def execute(node, user_inputs=None):
    user_inputs = user_inputs or {}
    resolved_args = {}
    
    for arg_name, value in node.func_arguments.items():
        if arg_name in node.pending_user_params:
            # 从用户输入中获取对应值,创建Automaton实例
            param_key = node.user_parameters[arg_name].lstrip('$')
            if param_key not in user_inputs:
                raise ValueError(f"缺少参数:{param_key}")
            resolved_args[arg_name] = Automaton(name=user_inputs[param_key])
        elif isinstance(value, FunctionNode):
            # 递归执行子节点
            resolved_args[arg_name] = execute(value, user_inputs)
        else:
            resolved_args[arg_name] = value
    
    # 调用实际函数并返回结果
    return node.func(**resolved_args)

4. 适配可变参数(如*args)

针对Sync这类带*args的函数,在初始化时识别可变参数并单独处理:

from inspect import signature, Parameter

class FunctionNode:
    def __init__(self, func, name=None, args=None):
        # 原有初始化代码...
        self.variable_args = None
        sig = signature(func)
        for param_name, param in sig.parameters.items():
            if param.kind == Parameter.VAR_POSITIONAL:
                self.variable_args = param_name
                self.pending_user_params.add(param_name)  # 标记为待输入
                break

后续可在GUI中为可变参数添加多个用户输入项,执行时将多个输入值打包为元组传入函数。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 20:15:54