在 Python 中,我们经常会遇到需要编写一个方法,该方法可以被不同的参数组合调用。默认值取决于类属性的值。例如,有一个类 MyClass,其具有一个方法 my_method()。my_method() 方法可以被调用,参数组合有以下几种:
my_method(a, b, c):a、b 和 c 是必需的。my_method(a, b, c, d, e):a、b 和 c 是必需的,d 和 e 是可选的(如果self.a的值为 something)。my_method(a, b, c, e, f):a、b 和 c 是必需的,e 和 f 是可选的(如果self.a的值为 something else)。e的默认值取决于self.a的值。
目前的参数检查方式如下:
class MyClass:
def __init__(self, ...):
self.a = something
def my_method(self, a, b, c, **kwargs):
# a, b, and c are always required
# if self.a = something, we have optional keyword arguments d and e
# if self.a = something else, we have optional keyword arguments e and f
# default for e depends on value of self.a
# argument checking
if self.a == something:
if 'd' in kwargs.keys():
d = kwargs['d']
else:
d = default value
if 'e' in kwargs.keys():
e = kwargs['e']
else:
e = default value
else:
if 'e' in kwargs.keys():
e = kwargs['e']
else:
e = default value (different from above)
if 'f' in kwargs.keys():
f = kwargs['f']
else:
f = default value
这种方法很冗长,而且容易出错。有没有更好的方法来实现参数检查呢?
2、解决方案
一种方法是使用 dict 类的 get() 函数。get() 函数可以从字典中获取指定键的值,如果键不存在,则返回默认值。例如,可以将以下代码替换为:
if self.a == something:
d = kwargs.get('d', defd)
e = kwargs.get('e', defe1)
else:
e = kwargs.get('e', defe2)
f = kwargs.get('f', deff)
这样,代码就简洁了很多。
另一种方法是使用 functools.partial() 函数。partial() 函数可以将一个函数的部分参数固定,返回一个新的函数。例如,可以将以下代码替换为:
def my_method_with_d_and_e(self, a, b, c, d, e):
# ...
def my_method_with_e_and_f(self, a, b, c, e, f):
# ...
if self.a == something:
my_method = functools.partial(my_method_with_d_and_e, self)
else:
my_method = functools.partial(my_method_with_e_and_f, self)
my_method(a, b, c, **kwargs)
这样,就可以根据 self.a 的值来选择不同的函数来调用。
还有一种方法是使用 argparse 模块。argparse 模块可以帮助你解析命令行参数。例如,可以将以下代码替换为:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('a')
parser.add_argument('b')
parser.add_argument('c')
parser.add_argument('-d', default=defd)
parser.add_argument('-e', default=defe1)
parser.add_argument('-f', default=deff)
args = parser.parse_args()
my_method(args.a, args.b, args.c, **vars(args))
这样,就可以使用命令行参数来调用 my_method() 方法。