Set argument equal to another argument's value by default
我见过很多次,在这里,Python程序员(包括我自己)希望给定函数中的一个变量在没有给定该值的情况下默认为另一个变量。
这是一个包含三个不同解决方案的演练,每个解决方案都增加了复杂性和健壮性。所以,向前!
这是给你的,如果你想说,我正在努力做到:1 2 | def my_fun(a, b, c=a): return str(a) + str(b) + str(c) |
在这个例子中,如果没有给出C,那么我们将在末尾附加一个str(a)。这很简单,只是一个简单的玩具示例,我不怀疑您的用例可能更复杂。但是,这不是语法上正确的python,并且不会运行,因为没有定义
1 2 3 | Traceback (most recent call last): File"<input>", line 1, in <module> NameError: name 'a' is not defined |
号
然而,我经常看到以下问题的公认答案:
- 不,这是不可能的
- 您应该使用
None 的默认值,然后检查该值是否为None 。
如果这听起来像是你遇到的问题,我希望我能帮上忙!
答案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)的可能输入实际上是单例
为了进一步解释这一点,使用以下变量调用函数:好的。
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〕。好的。
因此,在我的用例中,默认值
有关建议此解决方案的答案,请阅读以下内容:好的。
- 是否可以将默认参数设置为其他参数值?
- 变量默认值的python快捷方式为另一个变量值(如果没有)。
- 函数参数的默认值等于另一个参数
- 如何避免默认参数为空列表?
- python可选函数参数,默认为另一个参数的值
但是,如果这对你不起作用,那就继续读吧!好的。
上述第一个链接中的注释提到使用由
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' |
。
所以,我们结束了,对吧?是否有任何合理的方法可能不起作用?隐马尔可夫模型。。。可能不是!但我确实说过这是一个由三部分组成的答案,所以继续!;)好的。
为了完整性起见,让我们假设我们的程序在一个空间中运行,在这个空间中,每个可能的场景都是可能的。(这可能不是一个合理的假设,但我认为,只要有足够的关于计算机架构和对象选择实现的信息,就可以得出
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' |
。
等一下!我输入了三个参数,所以我应该看到三个参数的字符串连接在一起!好的。
*排队进入有不可预见后果的土地*好的。
我是说,实际上不是。回答:"这是微不足道的优势领域!或者它的同类是完全有保证的。好的。
这种感觉是对的!对于这个案例(可能是大多数案例),这真的不值得担心!好的。
但是,如果值得担心,或者你只是想在数学上满足于消除你所知道的所有边缘情况…向前的!好的。
好吧,经过长时间的锻炼,我们回来了!好的。
回想一下,目标是编写一个可能有
如果我们改变方法允许任意数量的变量,而不是默认地定义变量呢?好的。
因此,如果您正在寻找一种不影响潜在输入的解决方案,其中有效输入可以是
我对这个问题的解决方案是更改这个函数的命名,并用一个以前命名约定的函数包装这个函数,但是我们使用
在步骤中:好的。
1 | def cast_to_string_concat(*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)}.') |
号
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)}.') |
号
正如我最喜欢的计算机科学教授James Cain博士,一位非常清晰地提倡安全性和完整性的人所说,"计算是上下文的(sic)",所以一定要使用对你有用的东西!但对我来说,我将使用选项3;)好的。
谢谢你的阅读!好的。
-斯宾塞好的。
附录:接下来的三个链接建议使用类或导入语句的一些外观,但我选择了不走这条路。如果这看起来像你想要的,那就试试吧!好的。
For answers utilizing a class, read these:
Ok.
- https://www.oreilly.com/library/view/python-cookbook/0596001673/ch17s02.html
- https://www.oreilly.com/library/view/python-cookbook/0596001673/ch05s24.html
- https://www.revsys.com/tidbits/sentinel-values-python/
号
留给读者的练习:好的。
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 showsc == object() isFalse , andstr(c) == str(object()) is alsoFalse , and that's why I'm using the implementation from Martin Pieters.Ok.
号
好啊。