Python字典解包传参时触发意外关键字参数TypeError报错
问题背景
已实现的销售额计算函数get_sales代码如下:
def get_sales( sale_1: int, sale_2: int, sale_3: int, with_fees: bool = True, ) -> float: if with_fees is True: return (sale_1 + sale_2 + sale_3) * 0.95 else: return (sale_1 + sale_2 + sale_3)
测试用字典sales_test包含多个业务字段:
sales_test = {'sale_1': 100, 'sale_2': 75, 'sale_3': 92, 'revenue_1' : 400, 'revenue_2' : 219, 'city' : 'London' }
初始编写的advanced_sales函数直接对字典做全量解包传参:
from typing import Dict def advanced_sales( sales_test: Dict[str, int], with_fees: bool = True, ) -> float: sales = get_sales(**sales_test) return sales advanced_sales(sales_test)
运行时触发报错:
TypeError: get_sales() got an unexpected keyword argument 'revenue_1'
预期输出为253.64999999999998,即三笔销售额求和后扣除5%手续费的计算结果。
报错原因
使用**运算符解包字典传参时,Python会将字典内所有键值对作为关键字参数传入目标函数。get_sales仅定义了sale_1、sale_2、sale_3、with_fees四个参数,而传入的字典包含revenue_1、revenue_2、city三个不属于目标函数参数列表的键,因此触发类型错误。
另外初始实现未将advanced_sales接收的with_fees参数透传给get_sales,调用时修改手续费开关不会生效。
解决方案
方案1:手动提取所需参数(推荐,简单直观)
直接筛选get_sales计算需要的销售字段再传入函数,同时透传手续费开关参数:
from typing import Dict def advanced_sales( sales_test: Dict[str, int | str | bool], with_fees: bool = True, ) -> float: # 仅提取销售额计算需要的三个字段 valid_params = {key: sales_test[key] for key in ("sale_1", "sale_2", "sale_3")} return get_sales(**valid_params, with_fees=with_fees)
该方案无额外依赖,逻辑清晰,适合参数固定、数量少的场景。
方案2:自动匹配函数参数(适配后续参数变动)
如果后续get_sales的参数可能调整,可以用标准库inspect自动获取函数的参数列表,自动过滤字典里的冗余键,无需手动维护参数名:
import inspect from typing import Dict def advanced_sales( sales_test: Dict[str, int | str | bool], with_fees: bool = True, ) -> float: # 自动读取get_sales支持的所有参数名 support_params = inspect.signature(get_sales).parameters.keys() # 过滤出字典中存在、且函数支持的参数 valid_params = {k: v for k, v in sales_test.items() if k in support_params} return get_sales(**valid_params, with_fees=with_fees)
验证结果
修正后调用advanced_sales(sales_test),将返回预期值253.64999999999998,无运行报错。
内容的提问来源于stack exchange,提问作者equanimity
相关产品推荐
相关产品推荐

