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

时间:2013-06-17 21:36:01

标签: python python-3.x

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

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值等于传入的第一个参数。谢谢。

4 个答案:

答案 0 :(得分:23)

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

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

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

如果您需要能够指定None作为参数,请使用不同的标记值:

_sentinel = object()

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

现在,来电者可以将setLength设置为None,但不会将其视为默认设置。

答案 1 :(得分:6)

由于Python处理绑定和默认参数的方式......

标准方式是:

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

另一种选择是:

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

如果您不想使用默认值,则需要您明确使用perms(elements, setLength='something else')

答案 2 :(得分:5)

您应该执行以下操作:

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

答案 3 :(得分:2)

答案1:

上面的解决方案如下:

def cast_to_string_concat(a, b, c=None):
  c = a if c is None else c

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

尽管这种方法可以解决无数潜在的问题,(也许是您的)!我想编写一个函数,其中变量“ c”的可能输入确实是单例None,因此我不得不做更多的挖掘工作。

为进一步说明这一点,请使用以下变量调用函数:

A='A'
B='B'
my_var = None

收益:

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

用户可能期望由于他们使用三个变量来调用函数,因此它应该打印出三个变量,如下所示:

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

因此,即使在声明了该变量的情况下,该实现也会忽略它,因此这意味着该函数不再具有确定是否定义了变量“ c”的能力。

因此,对于我的用例,默认值为None并不能解决问题。

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


但是,如果那对您不起作用,那么也许继续阅读吧!


上面第一个链接中的注释使用了_sentinel定义的object()

因此,该解决方案删除了​​None的使用,并通过使用implied专用object()将其替换为sentinel


答案2:

_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)
A='A'
B='B'
C='C'

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

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

这真棒!可以正确处理上述边缘情况!亲自看看:


A='A'
B='B'
C = None

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

所以,我们完成了,对吧?有什么可行的方法可能不起作用?嗯...可能不是!但是我确实说过这是一个三部分的答案,所以继续吧! ;)


为了完整起见,让我们想象一下我们的程序在一个确实存在所有可能场景的空间中运行。 (这可能不是一个合理的假设,但我想人们可以利用有关计算机体系结构和对象选择的实现的足够信息来推导_sentinel的值。因此,如果您愿意,让我们假设确实存在这种可能性,让我们想象一下,我们决定测试参照上述定义的_sentinel的假设。


_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)
A='A'
B='B'
S = _sentinel

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

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


*队列进入意外后果之地*

我的意思是,实际上不是。回应为:“这是微不足道的情况!”或完全有理由保证。

那情绪是正确的!对于这种情况(可能是大多数情况),这确实不值得担心!

但是如果值得担心,或者如果您只是想消除所有边缘情况的数学上的满足,那么……起步!

  

锻炼留给读者:

     
    

与这种技术不同,您可以直接声明c=object(),但是,老实说,我还没有为我工作的那种方法。我的调查表明c == object()False,而str(c) == str(object())也是False,这就是为什么我使用Martin Pieters中的实现。

  

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

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

代替默认定义变量,如果我们改变方法以允许任意数量的变量,该怎么办?

因此,如果您正在寻找一种不影响潜在输入的解决方案,那么有效输入可以是Noneobject()_sentinel ...而且只有这样),在这一点上,我认为我的解决方案会有所帮助。该技术的灵感来自second part of Jon Clements' answer


答案3:

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

步骤:

  1. 将函数重命名为类似的内容
  2. 删除可选参数的默认设置
  3. 开始在上方创建一个新功能,然后在其中输入原始功能。
 def cast_to_string_concat(*args):
  1. 确定函数的 arem -(我在搜索中发现了那个单词……这是传递给给定函数的参数数量)
  2. 利用内部的case语句确定是否输入了有效数量的变量,并进行相应调整!
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)}.')

# instantiation

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

_sentinel = object()
S = _sentinel

N = None
""" 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 -最简单的答案,并且适用于大多数情况。
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通过object()切换到_sentinel实际上不表示空参数,则使用
_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任意包装的包装函数寻找通用解决方案,并处理内部可接受的情况:
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;)