if(foo或bar或baz)为None:

Jim*_*nis 8 python styles correctness

我一直在重构一些相当苛刻的代码,并遇到了以下相当奇怪的构造:

#!/usr/bin/env python2.7
# ...
if (opts.foo or opts.bar or opts.baz) is None:
    # (actual option names changed to protect the guilty)
    sys.stderr.write("Some error messages that these are required arguments")
Run Code Online (Sandbox Code Playgroud)

......我想知道这是否会产生任何可想象的感觉.

我将其更改为:

#!/usr/bin/env python2.7 
if None in (opts.foo, opts.bar, opts.baz):
    # ...
Run Code Online (Sandbox Code Playgroud)

我确实启动了一个解释器并实际尝试了第一个构造......只有当值全部为假并且这些错误值的最后一个为None时,它才会起作用.(换句话说,CPython的实现似乎从一个或多个表达式返回第一个真值或最后一个假值).

我仍然怀疑正确的代码应该使用添加了2.5 的any()all()内置函数(有问题的代码已经需要2.7).我还不确定哪个是首选的/预期的语义,因为我刚开始这个项目.

那么这个原始代码是否有意义呢?

Mar*_*zek 5

它的行为方式是因为它or是一个短路操作符,详细信息在docs中.因此,您的第一个if陈述等于:

if opts.baz is None
Run Code Online (Sandbox Code Playgroud)

我们可以猜出该代码的作者应该是什么.我认为,正如你所提到的,他想到了使用not all([opts.foo, opts.bar, opts.baz]).


Bre*_*arn 5

短路行为导致foo or bar or baz返回boolean-true的三个值中的第一个,或者如果all为boolean-false则返回最后一个值.所以它基本上意味着"如果所有都是假的,最后一个是无".

您更改的版本略有不同. if None in (opts.foo, opts.bar, opts.baz)例如,if如果opts.foo是None而另外两个是1则输入块,而原始版本不会(因为None or 1 or 1将评估为1,这不是None).您的版本将在三者中的任何一个为None if时输入,无论其他两个是什么,而原始版本将仅在最后一个为None 其他两个是任何boolean-false值时输入.if

要在两个版本的依赖于代码的其余部分的结构以及什么值的选项可能需要(特别是,他们是否可能有比无其他布尔假值,如False0或空字符串).直觉上你的版本似乎更合理,但如果代码中有这样的特殊技巧,你永远不会知道可能出现的角落案例.