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

如何实现addOrUpdate方法:仅更新指定参数且保留其余参数

实现支持创建/更新Feature实例的函数

需求说明

需要编写一个函数,同时满足两个功能:

  • 创建Feature类的新实例,并且支持为实例参数指定默认值
  • 修改现有Feature实例的指定参数,未明确指定的参数保持原有值不变

问题示例代码

以下代码展示了当前实现的问题:当更新现有实例时,未指定的参数会被函数默认值覆盖,而不是保留原有值。

class Feature:
    def __init__(self,
            title='DefaultTitle',
            number=-1):
        self.title = title
        self.number = number

def addOrUpdateFeature(
            existingFeature=None,
            title='NewTitle',
            number=0):
    if existingFeature:
        existingFeature.title = title
        existingFeature.number = number
        return True
    else:
        return Feature(title=title, number=number)

# 测试1:创建title='featureA'、number=1的新实例
a = addOrUpdateFeature(title='featureA', number=1)
print(f'part 1: title={a.title}  number={a.number}')

# 测试2:尝试仅修改实例的number,保留title不变
# 问题:当前代码会将title覆盖为函数默认值'NewTitle'
addOrUpdateFeature(existingFeature=a, number=2)
print(f'part 2: title={a.title}  number={a.number}')

运行结果

PS C:\Users\caver\Documents\GitHub> python argsTest.py
part 1: title=featureA  number=1
part 2: title=NewTitle  number=2

现有方案的局限

可以通过获取函数调用时的实际传入参数列表来解决问题,但这种方法需要将函数签名改为**kwargs,虽然调用方式友好,但函数签名不够直观简洁。

解决方案

方案一:使用**kwargs实现简洁调用(推荐)

直接通过关键字参数接收需要修改或设置的参数,创建实例时自动使用Feature类的默认值,更新时仅修改传入的参数:

class Feature:
    def __init__(self,
            title='DefaultTitle',
            number=-1):
        self.title = title
        self.number = number

def addOrUpdateFeature(existingFeature=None, **kwargs):
    if existingFeature:
        # 仅更新传入的参数,其余参数保持不变
        for key, value in kwargs.items():
            if hasattr(existingFeature, key):
                setattr(existingFeature, key, value)
        return True
    else:
        # 创建新实例,传入的参数优先,未传入的使用Feature的默认值
        return Feature(**kwargs)

# 测试验证
a = addOrUpdateFeature(title='featureA', number=1)
print(f'part 1: title={a.title}  number={a.number}')  # 输出:part 1: title=featureA  number=1

addOrUpdateFeature(existingFeature=a, number=2)
print(f'part 2: title={a.title}  number={a.number}')  # 输出:part 2: title=featureA  number=2

# 测试创建默认实例
b = addOrUpdateFeature()
print(f'part 3: title={b.title}  number={b.number}')  # 输出:part 3: title=DefaultTitle  number=-1

方案二:保留显式参数签名(借助inspect模块)

如果希望保留函数的显式参数签名,同时区分调用时的传入参数和默认值,可以使用inspect模块:

import inspect

class Feature:
    def __init__(self,
            title='DefaultTitle',
            number=-1):
        self.title = title
        self.number = number

def addOrUpdateFeature(existingFeature=None, title='NewTitle', number=0):
    # 获取函数签名和调用时的实际参数
    sig = inspect.signature(addOrUpdateFeature)
    frame = inspect.currentframe()
    args_info = inspect.getargvalues(frame)
    bound_args = sig.bind(*args_info.args)
    bound_args.apply_defaults()
    
    # 筛选出调用者显式传入的参数(排除existingFeature)
    passed_params = {}
    for param_name, param in sig.parameters.items():
        if param_name == 'existingFeature':
            continue
        # 判断参数是否是调用者显式传入的(而非使用默认值)
        if args_info.locals[param_name] != param.default:
            passed_params[param_name] = args_info.locals[param_name]

    if existingFeature:
        # 仅更新显式传入的参数
        for key, value in passed_params.items():
            setattr(existingFeature, key, value)
        return True
    else:
        # 创建新实例时,优先使用传入的参数,否则用Feature的默认值
        feature_params = {}
        feature_init_sig = inspect.signature(Feature.__init__)
        for param_name in ['title', 'number']:
            if param_name in passed_params:
                feature_params[param_name] = passed_params[param_name]
            else:
                # 获取Feature类的默认值
                feature_params[param_name] = feature_init_sig.parameters[param_name].default
        return Feature(**feature_params)

# 测试验证
a = addOrUpdateFeature(title='featureA', number=1)
print(f'part 1: title={a.title}  number={a.number}')  # 输出:part 1: title=featureA  number=1

addOrUpdateFeature(existingFeature=a, number=2)
print(f'part 2: title={a.title}  number={a.number}')  # 输出:part 2: title=featureA  number=2

# 测试创建默认实例
b = addOrUpdateFeature()
print(f'part 3: title={b.title}  number={b.number}')  # 输出:part 3: title=DefaultTitle  number=-1

方案对比

  • 方案一:代码简洁,调用方式灵活,完全满足需求,推荐使用。可以通过添加文档字符串来补充参数说明,弥补签名不直观的问题。
  • 方案二:保留了显式的参数签名,可读性更强,但代码相对复杂,依赖inspect模块。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 02:44:52