【问题标题】:Python: More elegant way to add optional parameters to method callPython:向方法调用添加可选参数的更优雅方式
【发布时间】:2017-05-31 05:55:20
【问题描述】:

这可能看起来微不足道,但这是我经常遇到的一种情况,我希望找到一种更优雅的方式来编写此代码。该方法虽然与问题不太相关,但需要一个文本值和一个可选的 is_checked 值来创建一个单选按钮(使用dominant)。在这种情况下,我不能将 'checked' 设置为 None 或 false - 它必须存在或不存在。看起来我不应该写两次“输入”行,只是为了可选地添加一个参数。

def _get_radio_button(text: str, is_checked=False):

    with label(text, cls="radio-inline") as lbl:
        if is_checked:
            input(text, type="radio", name="optradio", checked='checked')
        else:
            input(text, type="radio", name="optradio")

    return lbl

这将是我的第二种方法,但它是相同的代码行并且可读性较差 - 尽管可能更干燥一点。

a = dict(type='radio', name='optradio')
if is_checked: 
    a['checked']='checked'
with label(text, cls="radio-inline") as lbl:
    input(text, **a)

问题:如何在不牺牲可读性的情况下以尽可能少的行数处理此代码案例?

【问题讨论】:

  • 您的第二个选项非常合理,只需为 kwargs 字典使用一个合理的名称,例如 kwargs 而不是 a

标签: python python-3.x optional-parameters keyword-argument


【解决方案1】:

您的代码看起来不错,除了 a 的命名很明显,它可能是 input_opts 或类似的名称。

另一种使其更清晰的可能性是对常见的东西使用直接的关键字参数,并使用** 注入可选的参数。当只有一个是可选的时,这可以很短,例如:

checked_arg = {'checked': 'checked'} if is_checked else {}
with label(text, cls="radio-inline") as lbl:
    input(text, type="radio", name="optradio", **checked_arg)

【讨论】:

  • 我知道你在那里做了什么——我喜欢它。我怀疑这会得到答案,但想给它一点,看看是否还有其他东西弹出。感谢您抽出宝贵时间回复。
  • @SteveJ 另一个可能的选择是将其更改为“def f(text, **attrs)”,将内部函数调用为“input(..., **attrs)”并调用主要作为“f('some text',checked='checked')”,如果想要提供额外的属性,它可以说更明确并且可能更灵活,但这一切都取决于你希望它看起来/被使用的方式......跨度>
  • @JonClements 这也可以,但这种方法的问题在于它会将input 参数的构造暴露给_get_radio_button 的调用者——包括无法提供@ 的缺点checked 的 987654327@ 值。我会避免这种情况,除非从其余代码中可以清楚地看出_get_radio_button 只是调用input 的薄包装。
  • @user4815162342 确实-为什么我不愿将其建议为正确答案,并且就像您说的那样,在没有更多上下文的情况下很难判断。乍一看,input 是相当通用的,可能是 partial'd 用于不同的类型,然后将 **kwargs 扔给它......但是 耸耸肩 - 我们不知道。
  • 感谢 user4815162342 的回答和@JonClements 的额外讨论。我故意没有提供太多背景信息,因为我想为通用案例提供解决方案。这个解决方案正是我所要求的,干的、简单的、可读的。就其本身而言,它似乎没有太大区别,但这些线加起来。更重要的是,它为我提供了更多使用方法参数的工具。
【解决方案2】:

仅作为概念 :) 您可以以这种方式装饰自己的或外来(库)功能。更重要的是,您可以将装饰器作为类(使用将装饰底层函数的__call__ 方法),可以使用底层函数参数的简单“态射”进行参数化(它们可能是函数列表 - 作为装饰器类构造函数的参数)。您还可以制作更具声明性的装饰器并检查底层函数参数(例如,对于默认值)-您只受自己的幻想的限制:)所以:

from functools import wraps

def adapt_gui_args(callable):
    @wraps(callable)
    def w(*args, **kwargs):
        if kwargs.pop('is_checked', False): kwargs['checked'] = 'checked'
        return callable(*args, **kwargs)
    return w

# may be decorated with adapt_gui_args if it's your function
def input(*args, **kwargs):
    print("args: ", args)
    print("kwargs: ", kwargs)

# decorate input function outside its source body
input = adapt_gui_args(input)

def test(is_checked=False):
    input(1, 2, type="radio", is_checked=is_checked)

test(False)
test(True)

【讨论】:

  • (轻笑)——我几乎无法理解它,我想不出有什么时候它不会矫枉过正,但我​​喜欢它——谢谢你教我一些新东西。
  • 这个解决方案的问题在于,虽然adapt_gui_args 听起来很笼统,但实际上它与input 的语义密切相关(即使如此,也与它的单个checked 参数密切相关,该参数被转换来自is_checked)。这样的代码没有理由不驻留在test 中,就像在 OP 的代码中那样。另一方面,一个真正通用的装饰器版本,它接受描述转换的任意参数,如is_checked -> checked 实际上是有用的。
猜你喜欢
  • 2021-05-27
  • 2011-08-02
  • 1970-01-01
  • 1970-01-01
  • 2011-04-05
  • 1970-01-01
  • 2018-07-06
  • 2012-06-12
  • 1970-01-01
相关资源
最近更新 更多