luc*_*rot 29 python python-3.x
有一个带有可选参数的函数.
def alpha(p1="foo", p2="bar"):
print('{0},{1}'.format(p1, p2))
Run Code Online (Sandbox Code Playgroud)
让我迭代一下当我们以不同方式使用该函数时会发生什么:
>>> alpha()
foo,bar
>>> alpha("FOO")
FOO,bar
>>> alpha(p2="BAR")
foo,BAR
>>> alpha(p1="FOO", p2=None)
FOO,None
Run Code Online (Sandbox Code Playgroud)
现在考虑我想要调用它的情况,alpha("FOO", myp2)并且myp2将包含要传递的值,或者是None.但即使该函数处理p2=None,我希望它使用其默认值"bar".
也许这令人困惑,所以让我改写一下:
如果
myp2 is None,打电话alpha("FOO").不用了,打电话alpha("FOO", myp2).
区别是相关的,因为alpha("FOO", None)结果不同alpha("FOO").
我如何简洁(但可读)做出这种区分?
一种可能性通常是在内部检查无alpha,这将被鼓励,因为这将使代码更安全.但是假设alpha它实际上应该在其他地方使用,None就像它一样.
我想在来电方面处理这个问题.
一种可能性是区分案例:
if myp2 is None:
alpha("FOO")
else:
alpha("FOO", myp2)
Run Code Online (Sandbox Code Playgroud)
但是,当有多个这样的论点时,这很快就会成为很多代码.(指数,2 ^ n)
另一种可能性是简单地做alpha("FOO", myp2 or "bar"),但这需要我们知道默认值.通常,我可能会采用这种方法,但我可能稍后更改默认值,alpha然后需要手动更新此调用,以便仍然使用(新)默认值调用它.
我使用Python 3.4,但是这将是最好的,如果你的答案能够提供在任何Python版本工作的好办法.
这个问题在技术上完成了,但是我再次重新考虑了一些要求,因为第一个答案确实掩盖了这一点:
我希望保留alpha其默认值的行为"foo", "bar",因此它(可能)不是改变alpha自身的选项.
换句话说,假设在alpha其他alpha("FOO", None)地方使用输出FOO,None是预期行为的地方.
dec*_*eze 31
将参数作为kwargs从字典中传递出来,从中过滤掉None值:
kwargs = dict(p1='FOO', p2=None)
alpha(**{k: v for k, v in kwargs.items() if v is not None})
Run Code Online (Sandbox Code Playgroud)
虽然**绝对是一种语言功能,但它肯定不是为解决这个特殊问题而创建的.你的建议是有效的,我的也是如此.哪一个更好用取决于OP代码的其余部分.但是,仍然没有办法写
f(x or dont_pass_it_at_all)- blue_note
感谢你的好答案,我想我会尽力做到这一点:
# gen.py
def callWithNonNoneArgs(f, *args, **kwargs):
kwargsNotNone = {k: v for k, v in kwargs.items() if v is not None}
return f(*args, **kwargsNotNone)
Run Code Online (Sandbox Code Playgroud)
# python interpreter
>>> import gen
>>> def alpha(p1="foo", p2="bar"):
... print('{0},{1}'.format(p1,p2))
...
>>> gen.callWithNonNoneArgs(alpha, p1="FOO", p2=None)
FOO,bar
>>> def beta(ree, p1="foo", p2="bar"):
... print('{0},{1},{2}'.format(ree,p1,p2))
...
>>> beta('hello', p2="world")
hello,foo,world
>>> beta('hello', p2=None)
hello,foo,None
>>> gen.callWithNonNoneArgs(beta, 'hello', p2=None)
hello,foo,bar
Run Code Online (Sandbox Code Playgroud)
这可能并不完美,但它似乎有效:它是一个函数,你可以调用另一个函数和它的参数,它应用deceze的答案来过滤掉那些参数None.
但是假设alpha实际上应该用于处理None的其他地方.
为了回应这个问题,我知道有一个类似None的值,实际上并不是None出于这个目的.
_novalue = object()
def alpha(p1=_novalue, p2=_novalue):
if p1 is _novalue:
p1 = "foo"
if p2 is _novalue:
p2 = "bar"
print('{0},{1}'.format(p1, p2))
Run Code Online (Sandbox Code Playgroud)
现在参数仍然是可选的,所以你可以忽略它们中的任何一个.并且该功能None正确处理.如果你想明确地不传递参数,你可以传递_novalue.
>>> alpha(p1="FOO", p2=None)
FOO,None
>>> alpha(p1="FOO")
FOO,bar
>>> alpha(p1="FOO", p2=_novalue)
FOO,bar
Run Code Online (Sandbox Code Playgroud)
并且由于_novalue是为此明确目的而创建的特殊组合值,任何通过_novalue的人当然都打算采用"默认参数"行为,而不是None那些可能意图将该值解释为文字的人None.
您可以通过检查默认值alpha.__defaults__,然后使用它们而不是None。这样你就可以绕过默认值的硬编码:
>>> args = [None]
>>> alpha('FOO', *[x if x is not None else y for x, y in zip(args, alpha.__defaults__[1:])])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6361 次 |
| 最近记录: |