如何以Pythonic方式在两个函数间传递带可选性的参数?
解决嵌套函数可选参数传递的Pythonic方案
嘿,这个问题我碰到过不少次!核心问题其实是你把foo里的opt=None当成了“未传入参数”的标记,但实际上当你调用foo(1)时,opt被明确赋值为None,然后你把这个None传给了bar——而bar的默认值5只会在没有收到opt参数的时候才会生效,所以自然输出None啦。
不用写冗余的判断逻辑,也不用重复定义默认值,有两种很Pythonic的办法解决:
方法一:用哨兵对象区分“未传入”和“传入None”
我们可以创建一个独一无二的对象作为foo中opt的默认值,这个对象和任何其他值都不相等,用来精准判断用户是否真的传入了参数:
# 造个独一无二的哨兵,专门用来标记参数没被传入 _sentinel = object() def foo(x1, opt=_sentinel): if opt is _sentinel: # 用户没传opt,直接调用bar,让它用自己的默认值 bar() else: # 用户传了opt(哪怕是None),直接传过去 bar(opt) def bar(opt=5): print(opt) if __name__ == '__main__': foo(1) # 输出5,完美符合预期 foo(2, opt=3) # 输出3,正常工作 foo(3, opt=None)# 输出None,因为用户明确传了None
这个方法的好处是绝对不会和用户传入的任何值混淆,哪怕你需要支持传入None作为合法参数也没问题,而且完全遵守DRY原则——bar的默认值只定义了一次。
方法二:用可变关键字参数传递参数
如果foo的可选参数和bar的对应关系很明确,直接用**kwargs打包传递参数更简洁:
def foo(x1, **kwargs): # 把收到的关键字参数原样传给bar,没收到opt的话,bar就用自己的默认值 bar(**kwargs) def bar(opt=5): print(opt) if __name__ == '__main__': foo(1) # 输出5 foo(2, opt=3) # 输出3 foo(3, opt=None)# 输出None
这种写法代码更少,看起来更清爽,唯一需要注意的是如果foo有其他可选关键字参数,要确保bar能接受,或者在传递前过滤掉无关参数(当然如果参数对应关系明确的话,直接传就好)。
这两种方法都能完美解决你的问题,不用写冗余的判断,也不会重复定义默认值,完全是Python推荐的写法~
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

