python - 重构处理“默认参数覆盖”的微小代码
问题描述
我有一个 python(2.7) 类,它结束了调用一些 bash 命令。这里重要的是,期望在下面调用的那些命令需要传递大量参数。这就是为什么我想允许在类的构造函数中设置这些参数,这种过度简化看起来像这样:
def __init__(self, foo=None, baz=None, bar=None):
self._executor = BashExecutor()
self._foo = foo
self._baz = baz
self._bar = bar
此类还具有一些功能,允许在一次 bash 执行范围内覆盖这些参数(但不强制)。这意味着函数签名可以如下所示:
def execute(self, foo=None, baz=None, bar=None, sup=None):
然后是“有问题的部分”。每个参数可以在函数范围内传递,在对象的构造函数中给出,或者根本不传递(在函数中传递它比构造函数具有更高的优先级)。因此,我有以下代码片段:
foo = foo or self._foo
if foo:
params.append(<<somehow formatted foo>>)
这些只是 3 行,但它们使用具有不同格式的不同参数重复多次......
这不能以某种方式简化吗?
说明问题的完整示例如下所示:
class BashExecutor(object):
def execute(self, command):
print command
class Example(object):
def __init__(self, foo=None, baz=None, bar=None):
self._executor = BashExecutor()
self._foo = foo
self._baz = baz
self._bar = bar
def execute(self, foo=None, baz=None, bar=None, sup=None):
params = []
foo = foo or self._foo
if foo:
params.append("--foo_param %s" % foo)
baz = baz or self._baz
if baz:
params.append("--baz_param %s" % baz)
bar = bar or self._bar
if bar:
params.append("--additional_param bar=%s" % bar)
sup = sup or []
if sup:
params.append("--additional_param sup=%s" % ",".join(sup))
self._executor.execute("application %s" % " ".join(params))
ex = Example(foo=1, bar=2)
ex.execute(foo=3, sup=[ "abc", "def" ])
解决方案
你可以这样做:
class Solution(object):
_ALLOWED_USER = ['cake', 'chocolate', 'creme_brulee']
_ALLOWED_VARS = ['broccoli', 'avocado', 'spinach']
def __init__(self, **kwargs):
self._validate_kwargs(kwargs)
for key, value in kwargs.iteritems():
setattr(self, '_{}'.format(key), value)
def _validate_kwargs(self, kwargs):
unrecognised = {key for key in kwargs if key not in self._ALLOWED_USER + self._ALLOWED_VARS}
if unrecognised:
raise ValueError('The following unrecognised arguments were passed: {}'.format(unrecognised))
def _populate(self, iterable, allowed, format_string):
result = []
for key in allowed:
attribute_name = '_{}'.format(key)
if key in iterable:
result.append(format_string.format(key, iterable[key]))
elif hasattr(self, attribute_name):
result.append(format_string.format(key, getattr(self, attribute_name)))
return result
def execute(self, **kwargs):
self._validate_kwargs(kwargs)
user_args = self._populate(kwargs, self._ALLOWED_USER, '--{}_param {}')
vars_args = self._populate(kwargs, self._ALLOWED_VARS, '--additional_param {}={}')
print(user_args + vars_args)
my_solution = Solution(cake='tasty', broccoli='icky', avocado='awesome')
my_solution.execute(creme_brulee='great', broccoli='okay, I guess', spinach='meh', cake='really tasty')
输出:
['--cake_param really tasty', '--creme_brulee_param great', '--additional_param broccoli=okay, I guess', '--additional_param avocado=awesome', '--additional_param spinach=meh']
您可以看到 和 的实例值cake
已broccoli
被传递给函数的实例值覆盖。
这个想法基本上是在所有相关路径中分解出不变的内容,并通过参数提供可定制性。通过将user
参数与vars
参数分开并使用**kwargs
,我们可以实现输入验证,同时具有灵活性和每种参数类型的不同输出。
参数覆盖实例变量的行为可以通过首先检查传递的参数中每个参数的存在,然后在实例的属性中使用hasattr
.
我现在无法访问 Python 2,但这应该可以。
推荐阅读
- asp.net-mvc - Javascript 文件不在 lib 文件夹中
- sql - 在 Oracle 中使用 DB Link 调用函数
- ruby - 块内未定义外部范围的 Ruby 变量 - 为什么?
- scala - 为什么 sbt 不选择范围内最新的依赖版本?
- php - 将 soapenv:mustUnderstand="1" 属性添加到带有 SimpleXMLElement 对象的 SOAP 请求的标头中的安全标记
- ember.js - 什么是 ember 中的 node_modules 目录
- python - 熊猫数据框日期列中日期格式的转换不一致
- html - 使用angular6从mongodb获取图像到网站
- java - 在 Android 中迭代可绘制对象
- c++ - 案例“错误列表”:会发生什么?