Python类方法如何优雅统一定义公共默认参数
统一类方法重复默认参数的实现方案
方案1:类级常量统一定义(最小改动,无额外依赖)
把公共默认值统一定义为类属性,方法参数用None作为哨兵占位,方法内部判断未传参时引用类属性的默认值。该方案完全保留单次调用传参自定义的灵活性,修改全局默认值仅需调整类属性一处,不会出现多方法改漏的问题。
示例代码:class Test: # 公共默认值统一维护区 _DEFAULT_VERBOSE = True _DEFAULT_DELIM = '\t' _DEFAULT_LVL = 0 def f1(self, a, b, verbose=None, delim=None, lvl=None): verbose = self._DEFAULT_VERBOSE if verbose is None else verbose delim = self._DEFAULT_DELIM if delim is None else delim lvl = self._DEFAULT_LVL if lvl is None else lvl # 原有业务逻辑 ... def f2(self, c, verbose=None, delim=None, lvl=None): verbose = self._DEFAULT_VERBOSE if verbose is None else verbose delim = self._DEFAULT_DELIM if delim is None else delim lvl = self._DEFAULT_LVL if lvl is None else lvl # 原有业务逻辑 ... def f3(self, d, e, f, verbose=None, delim=None, lvl=None): verbose = self._DEFAULT_VERBOSE if verbose is None else verbose delim = self._DEFAULT_DELIM if delim is None else delim lvl = self._DEFAULT_LVL if lvl is None else lvl # 原有业务逻辑 ...注意:不要直接把类属性写在方法定义的默认参数位置,Python函数默认值在函数定义阶段就会固定,后续修改类属性不会同步更新方法的默认参数。
方案2:装饰器统一注入默认参数(适合方法数量多的场景)
如果类里带公共参数的方法很多,可以写一个专用装饰器统一处理默认值逻辑,省去每个方法里重复写参数判断的冗余代码。
示例代码:from functools import wraps def inject_common_defaults(func): @wraps(func) def wrapper(self, *args, verbose=None, delim=None, lvl=None, **kwargs): # 统一处理默认值赋值逻辑 verbose = self._DEFAULT_VERBOSE if verbose is None else verbose delim = self._DEFAULT_DELIM if delim is None else delim lvl = self._DEFAULT_LVL if lvl is None else lvl return func(self, *args, verbose=verbose, delim=delim, lvl=lvl, **kwargs) return wrapper class Test: _DEFAULT_VERBOSE = True _DEFAULT_DELIM = '\t' _DEFAULT_LVL = 0 @inject_common_defaults def f1(self, a, b, verbose, delim, lvl): # 方法内部直接使用参数即可,无需重复处理默认值 ... @inject_common_defaults def f2(self, c, verbose, delim, lvl): ... @inject_common_defaults def f3(self, d, e, f, verbose, delim, lvl): ...方案3:实例级默认配置(适合需要多实例差异化默认值的场景)
如果需要不同的类实例拥有不同的默认参数配置,可以把公共参数放到实例初始化方法里定义,方法调用时传参则覆盖实例配置,不传则使用实例自身的默认值。
示例代码:class Test: def __init__(self, verbose=True, delim='\t', lvl=0): # 每个实例可以自定义专属默认配置 self.default_verbose = verbose self.default_delim = delim self.default_lvl = lvl def f1(self, a, b, verbose=None, delim=None, lvl=None): verbose = self.default_verbose if verbose is None else verbose delim = self.default_delim if delim is None else delim lvl = self.default_lvl if lvl is None else lvl ... def f2(self, c, verbose=None, delim=None, lvl=None): verbose = self.default_verbose if verbose is None else verbose delim = self.default_delim if delim is None else delim lvl = self.default_lvl if lvl is None else lvl ...这个方案下既可以全局统一默认值,也可以创建特殊配置的实例,比如
test_special = Test(lvl=1),该实例调用所有方法时默认lvl=1,不需要每次调用都传参,单次调用传lvl=2依然可以临时覆盖配置。
以上所有方案都完全保留参数自定义的灵活性,比如调用f2时传入lvl=1的用法完全不受影响,公共默认值仅需维护一处,从根源上避免重复书写默认参数导致的改漏、值不一致问题。
内容的提问来源于stack exchange,提问作者yvrob
相关产品推荐
相关产品推荐

