关于python:有没有办法将默认参数设置为等于另一个参数值?

Is there a way to set a default parameter equal to another parameter value?

例如,我有一个返回排列列表的基本方法。

1
2
3
4
5
6
import itertools
def perms(elements, set_length=elements):
    data=[]
    for x in range(elements):
        data.append(x+1)
    return list(itertools.permutations(data, set_length))

现在我明白了,在当前状态下,这段代码不会运行,因为第二个elements没有定义,但是是否有优雅的方法来完成我在这里要做的工作?如果还不清楚,我想让默认的setLength值等于传入的第一个参数。谢谢。


否,函数关键字参数默认值是在定义函数时确定的,而不是在执行函数时确定的。

将默认值设置为None并检测到:

1
2
3
def perms(elements, setLength=None):
    if setLength is None:
        setLength = elements

如果需要指定None作为参数,请使用不同的sentinel值:

1
2
3
4
5
_sentinel = object()

def perms(elements, setLength=_sentinel):
    if setLength is _sentinel:
        setLength = elements

现在呼叫者可以将setLength设置为None,它不会被视为默认值。


因为python处理绑定和默认参数的方式…

标准方法是:

1
2
3
def perms(elements, setLength=None):
    if setLength is None:
        setLength = elements

另一个选择是:

1
2
def perms(elements, **kwargs):
    setLength = kwargs.pop('setLength', elements)

尽管这要求您明确使用perms(elements, setLength='something else'),如果您不希望出现默认值…


你应该这样做:

1
2
3
def perms(elements,setLength=None):
    if setLength is None:
        setLength = elements

答案1:

上面的解决方案如下:好的。

1
2
3
4
def cast_to_string_concat(a, b, c=None):
  c = a if c is None else c

  return str(a) + str(b) + str(c)

虽然这种方法可以解决大量的潜在问题(也许还有你的问题)!我想写一个函数,其中变量"EDOCX1"(0)的可能输入实际上是单例None,所以我需要做更多的挖掘。好的。

为了进一步解释这一点,使用以下变量调用函数:好的。

1
2
3
A='A'
B='B'
my_var = None

产量:好的。

1
2
cast_to_string_concat(A, B, my_var):
>>>'ABA'

然而,用户可能期望,因为他们使用三个变量调用函数,所以它应该打印三个变量,如下所示:好的。

1
2
cast_to_string_concat(A, B, my_var):
>>> 'ABNone' # simulated and expected outcome

因此,即使声明了第三个变量,这个实现也忽略了它,因此这意味着函数不再能够确定是否定义了变量"EDOCX1"〔0〕。好的。

因此,在我的用例中,默认值None并不能完全做到这一点。好的。

有关建议此解决方案的答案,请阅读以下内容:好的。

  • 是否可以将默认参数设置为其他参数值?
  • 变量默认值的python快捷方式为另一个变量值(如果没有)。
  • 函数参数的默认值等于另一个参数
  • 如何避免默认参数为空列表?

但是,如果这对你不起作用,那就继续读吧!好的。

上面第一个链接中的注释提到使用由object()定义的_sentinel。好的。

因此,该解决方案取消了none的使用,并通过使用隐含的私有sentinel将其替换为object()。好的。答案2:

1
2
3
4
5
_sentinel = object()
def cast_to_string_concat(a, b, c=_sentinel):
  c = a if c == _sentinel else c

  return str(a) + str(b) + str(c)
1
2
3
4
5
6
7
8
9
A='A'
B='B'
C='C'

cast_to_string_append(A,B,C)
>>> 'ABC'

cast_to_string_concat(A,B)
>>> 'ABA'

这真是太棒了!它能正确处理上面的边缘箱!自己看看:好的。

1
2
3
4
5
6
A='A'
B='B'
C = None

cast_to_string_concat(A, B, C)
>>> 'ABNone'

所以,我们结束了,对吧?是否有任何合理的方法可能不起作用?隐马尔可夫模型。。。可能不是!但我确实说过这是一个由三部分组成的答案,所以继续!;)好的。

为了完整性起见,让我们假设我们的程序在一个空间中运行,在这个空间中,每个可能的场景都是可能的。(这可能不是一个合理的假设,但我认为,只要有足够的关于计算机架构和对象选择实现的信息,就可以得出_sentinel的价值。所以,如果你愿意的话,让我们假设这确实是可能的,让我们设想一下,我们决定参照上述定义的_sentinel来检验这个假设。好的。

1
2
3
4
5
_sentinel = object()
def cast_to_string_concat(a, b, c=_sentinel):
  c = a if c == _sentinel else c

  return str(a) + str(b) + str(c)
1
2
3
4
5
6
A='A'
B='B'
S = _sentinel

cast_to_string_append(A,B,S)
>>> 'ABA'

等一下!我输入了三个参数,所以我应该看到三个参数的字符串连接在一起!好的。

*排队进入有不可预见后果的土地*好的。

我是说,实际上不是。回答:"这是微不足道的优势领域!或者它的同类是完全有保证的。好的。

这种感觉是对的!对于这个案例(可能是大多数案例),这真的不值得担心!好的。

但是,如果值得担心,或者你只是想在数学上满足于消除你所知道的所有边缘情况…向前的!好的。

Exercise left to reader:

Ok.

Deviating from this technique, you can directly assert c=object(), however, in honesty, I haven't gotten that way to work for me. My investigation shows c == object() is False, and str(c) == str(object()) is also False, and that's why I'm using the implementation from Martin Pieters.

Ok.

好吧,经过长时间的锻炼,我们回来了!好的。

回想一下,目标是编写一个可能有n输入的函数,并且只有在没有提供一个变量的情况下,您才会复制位置i中的另一个变量。好的。

如果我们改变方法允许任意数量的变量,而不是默认地定义变量呢?好的。

因此,如果您正在寻找一种不影响潜在输入的解决方案,其中有效输入可以是Noneobject()_sentinel…然后(只有在那时),在这一点上,我认为我的解决方案将是有帮助的。这项技术的灵感来自乔恩·克莱门茨回答的第二部分。好的。答案3:

我对这个问题的解决方案是更改这个函数的命名,并用一个以前命名约定的函数包装这个函数,但是我们使用*args,而不是使用变量。然后在本地范围内定义原始函数(使用新名称),并且只允许您希望的几种可能性。好的。

在步骤中:好的。

  • 将函数重命名为类似的内容
  • 删除可选参数的默认设置
  • 开始在上面创建一个新函数,并在中标记原始函数。
  • 1
     def cast_to_string_concat(*args):
  • 确定你的函数的arity(我在搜索中找到了那个词…这是传递给给定函数的参数数目)
  • 使用内部的case语句来确定是否输入了有效数量的变量,并相应地进行调整!
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def cast_to_string_append(*args):

        def string_append(a, b, c):
            # this is the original function, it is only called within the wrapper
            return str(a) + str(b) + str(c)

        if len(args) == 2:
            # if two arguments, then set the third to be the first
            return string_append(*args, args[0])

        elif len(args) == 3:
            # if three arguments, then call the function as written
            return string_append(*args)

        else:
            raise Exception(f'Function: cast_to_string_append() accepts two or three arguments, and you entered {len(args)}.')

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # instantiation

    A='A'
    B='B'
    C='C'
    D='D'

    _sentinel = object()
    S = _sentinel

    N = None
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    """ Answer 3 Testing"""

    # two variables

    cast_to_string_append(A,B)

    >>> 'ABA'


    # three variables

    cast_to_string_append(A,B,C)

    >>> 'ABC'


    # three variables, one is _sentinel

    cast_to_string_append(A,B,S)

    >>>'AB<object object at 0x10c56f560>'


    # three variables, one is None

    cast_to_string_append(A,B,N)

    >>>'ABNone'


    # one variable

    cast_to_string_append(A)

    >>>Traceback (most recent call last):
    >>>  File"<input>", line 1, in <module>
    >>>  File"<input>", line 13, in cast_to_string_append
    >>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 1.

    # four variables

    cast_to_string_append(A,B,C,D)

    >>>Traceback (most recent call last):
    >>>  File"<input>", line 1, in <module>
    >>>  File"<input>", line 13, in cast_to_string_append
    >>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 4.


    # ten variables

    cast_to_string_append(0,1,2,3,4,5,6,7,8,9)

    >>>Traceback (most recent call last):
    >>>  File"<input>", line 1, in <module>
    >>>  File"<input>", line 13, in cast_to_string_append
    >>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 10.


    # no variables

    cast_to_string_append()

    >>>Traceback (most recent call last):
    >>>  File"<input>", line 1, in <module>
    >>>  File"<input>", line 13, in cast_to_string_append
    >>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 0.

    """ End Answer 3 Testing"""

    。所以,总而言之:

    • 答案1-最简单的答案,适用于大多数情况。
    1
    2
    3
    4
    def cast_to_string_concat(a, b, c=None):
      c = a if c is None else c

      return str(a) + str(b) + str(c)
    • 回答2—如果None实际上没有通过_sentinel切换到object()表示空参数,则使用。
    1
    2
    3
    4
    5
    _sentinel = object()
    def cast_to_string_concat(a, b, c=_sentinel):
      c = a if c == _sentinel else c

      return str(a) + str(b) + str(c)

    • 答案3:使用*args寻找一个使用任意数量包装函数的一般解决方案,并处理可接受的内部情况:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def cast_to_string_append(*args):

        def string_append(a, b, c):
            # this is the original function, it is only called within the wrapper
            return str(a) + str(b) + str(c)

        if len(args) == 2:
            # if two arguments, then set the third to be the first
            return string_append(*args, args[0])

        elif len(args) == 3:
            # if three arguments, then call the function as written
            return string_append(*args)

        else:
            raise Exception(f'Function: cast_to_string_append() accepts two or three arguments, and you entered {len(args)}.')

    用对你有用的东西!但对我来说,我将使用选项3;)好的。好啊。