“如果 a 或 b 或 c 但不是全部”的 Python 语法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16522111/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 22:54:42  来源:igfitidea点击:

Python syntax for "if a or b or c but not all of them"

pythonif-statement

提问by Chris Wilson

I have a python script that can receive either zero or three command line arguments. (Either it runs on default behavior or needs all three values specified.)

我有一个 python 脚本,它可以接收零个或三个命令行参数。(要么以默认行为运行,要么需要指定所有三个值。)

What's the ideal syntax for something like:

什么是理想的语法如下:

if a and (not b or not c) or b and (not a or not c) or c and (not b or not a):

?

?

采纳答案by Stefano Sanfilippo

If you mean a minimal form, go with this:

如果您的意思是最小形式,请使用以下方法:

if (not a or not b or not c) and (a or b or c):

Which translates the title of your question.

这翻译了你的问题的标题。

UPDATE: as correctly said by Volatility and Supr, you can apply De Morgan's law and obtain equivalent:

更新:正如 Volatility 和 Supr 正确所说的那样,您可以应用德摩根定律并获得等效项:

if (a or b or c) and not (a and b and c):

My advice is to use whichever form is more significant to you and to other programmers. The first means "there is something false, but also something true", the second "There is something true, but not everything". If I were to optimize or do this in hardware, I would choose the second, here just choose the most readable (also taking in consideration the conditions you will be testing and their names). I picked the first.

我的建议是使用对您和其他程序员更重要的形式。第一个意思是“有一些是假的,但也有一些是真的”,第二个意思是“有一些是真的,但不是一切”。如果我要优化或在硬件中执行此操作,我会选择第二个,这里只选择最易读的(还要考虑您将要测试的条件及其名称)。我选了第一个。

回答by defuz

How about:

怎么样:

conditions = [a, b, c]
if any(conditions) and not all(conditions):
   ...

Other variant:

其他变体:

if 1 <= sum(map(bool, conditions)) <= 2:
   ...

回答by eumiro

This returns Trueif one and only one of the three conditions is True. Probably what you wanted in your example code.

这种回报True,如果有且仅有的三个条件之一True。可能是您在示例代码中想要的。

if sum(1 for x in (a,b,c) if x) == 1:

回答by Jon Clements

I'd go for:

我会去:

conds = iter([a, b, c])
if any(conds) and not any(conds):
    # okay...

I think this should short-circuit fairly efficiently

我认为这应该相当有效地短路

Explanation

解释

By making condsan iterator, the first use of anywill short circuit and leave the iterator pointing to the next element if any item is true; otherwise, it will consume the entire list and be False. The next anytakes the remaining items in the iterable, and makes sure than there aren't any other true values... If there are, the whole statement can't be true, thus there isn't one unique element (so short circuits again). The last anywill either return Falseor will exhaust the iterable and be True.

通过创建conds迭代器,第一次使用any将短路并让迭代器指向下一个元素,如果任何项为真;否则,它将消耗整个列表并且为False。下一个any获取迭代中的剩余项目,并确保没有任何其他真值......如果有,整个陈述就不可能是真的,因此没有一个唯一的元素(所以短路再次)。最后一个any将返回False或将耗尽可迭代对象为True

note: the above checks if only a single condition is set

注意:上面检查是否只设置了一个条件



If you want to check if one or more items, but not every item is set, then you can use:

如果要检查是否设置了一个或多个项目,但不是每个项目都已设置,则可以使用:

not all(conds) and any(conds)

回答by Casimir et Hippolyte

What about: (unique condition)

怎么样:(唯一条件)

if (bool(a) + bool(b) + bool(c) == 1):

Notice, if you allow two conditions too you could do that

注意,如果你也允许两个条件,你可以这样做

if (bool(a) + bool(b) + bool(c) in [1,2]):

回答by wim

This question already had many highly upvoted answers and an accepted answer, but all of them so far were distracted by various ways to express the boolean problem and missed a crucial point:

这个问题已经有许多高度赞成的答案和一个被接受的答案,但到目前为止,所有这些都被表达布尔问题的各种方式分散了注意力,并错过了一个关键点:

I have a python script that can receive either zero or three command line arguments. (Either it runs on default behavior or needs all three values specified)

我有一个 python 脚本,它可以接收零个或三个命令行参数。(要么以默认行为运行,要么需要指定所有三个值)

This logic should not be the responsibility of your code in the first place, rather it should be handled by argparsemodule. Don't bother writing a complex if statement, instead prefer to setup your argument parser something like this:

这个逻辑首先不应该是你的代码的责任,而应该由argparse模块处理。不要费心编写复杂的 if 语句,而是更喜欢设置参数解析器,如下所示:

#!/usr/bin/env python
import argparse as ap
parser = ap.ArgumentParser()
parser.add_argument('--foo', nargs=3, default=['x', 'y', 'z'])
args = parser.parse_args()
print(args.foo)

And yes, it should be an optionnot a positional argument, because it is after all optional.

是的,它应该是一个选项而不是位置参数,因为它毕竟是optional



edited:To address the concern of LarsH in the comments, below is an example of how you could write it if you were certain you wanted the interface with either 3 or 0 positionalargs. I am of the opinion that the previous interface is better style, because optionalarguments should be options, but here's an alternative approach for the sake of completeness. Note the overriding kwarg usagewhen creating your parser, because argparsewill auto-generate a misleading usage message otherwise!

编辑:为了解决评论中 LarsH 的问题,下面是一个示例,说明如果您确定想要具有 3 或 0位置参数的接口,您可以如何编写它。我认为以前的界面风格更好,因为可选参数应该是options,但为了完整起见,这里有一个替代方法。usage在创建解析器时请注意覆盖的 kwarg,argparse否则会自动生成误导性的使用消息!

#!/usr/bin/env python
import argparse as ap
parser = ap.ArgumentParser(usage='%(prog)s [-h] [a b c]\n')
parser.add_argument('abc', nargs='*', help='specify 3 or 0 items', default=['x', 'y', 'z'])
args = parser.parse_args()
if len(args.abc) != 3:
  parser.error('expected 3 arguments')
print(args.abc)

Here are some usage examples:

以下是一些使用示例:

# default case
wim@wim-zenbook:/tmp$ ./three_or_none.py 
['x', 'y', 'z']

# explicit case
wim@wim-zenbook:/tmp$ ./three_or_none.py 1 2 3
['1', '2', '3']

# example failure mode
wim@wim-zenbook:/tmp$ ./three_or_none.py 1 2 
usage: three_or_none.py [-h] [a b c]
three_or_none.py: error: expected 3 arguments

回答by Inbar Rose

As I understand it, you have a function that receives 3 arguments, but if it does not it will run on default behavior. Since you have not explained what should happen when 1 or 2 arguments are supplied I will assume it should simply do the default behavior. In which case, I think you will find the following answer very advantageous:

据我了解,您有一个接收 3 个参数的函数,但如果没有,它将以默认行为运行。由于您没有解释提供 1 或 2 个参数时会发生什么,我假设它应该只是执行默认行为。在这种情况下,我认为您会发现以下答案非常有利:

def method(a=None, b=None, c=None):
    if all([a, b, c]):
        # received 3 arguments
    else:
        # default behavior

However, if you want 1 or 2 arguments to be handled differently:

但是,如果您希望以不同方式处理 1 或 2 个参数:

def method(a=None, b=None, c=None):
    args = [a, b, c]
    if all(args):
        # received 3 arguments
    elif not any(args):
        # default behavior
    else:
        # some args (raise exception?)

note:This assumes that "False" values will not be passed into this method.

注意:这假设“ False”值不会传递到此方法中。

回答by Janus Troelsen

If you work with an iterator of conditions, it could be slow to access. But you don't need to access each element more than once, and you don't always need to read all of it. Here's a solution that will work with infinite generators:

如果您使用条件迭代器,则访问速度可能会很慢。但是您不需要多次访问每个元素,也不必总是阅读所有元素。这是一个适用于无限生成器的解决方案:

#!/usr/bin/env python3
from random import randint
from itertools import tee

def generate_random():
    while True:
        yield bool(randint(0,1))

def any_but_not_all2(s): # elegant
    t1, t2 = tee(s)
    return False in t1 and True in t2 # could also use "not all(...) and any(...)"

def any_but_not_all(s): # simple
    hadFalse = False
    hadTrue = False
    for i in s:
        if i:
            hadTrue = True
        else:
            hadFalse = True
        if hadTrue and hadFalse:
            return True
    return False


r1, r2 = tee(generate_random())
assert any_but_not_all(r1)
assert any_but_not_all2(r2)

assert not any_but_not_all([True, True])
assert not any_but_not_all2([True, True])

assert not any_but_not_all([])
assert not any_but_not_all2([])

assert any_but_not_all([True, False])
assert any_but_not_all2([True, False])

回答by Relaxing In Cyprus

The question states that you need either all three arguments (a and b and c) or none of them (not (a or b or c))

问题指出您需要所有三个参数(a 和 b 和 c)或不需要它们(不是(a 或 b 或 c))

This gives:

这给出:

(a and b and c) or not (a or b or c)

(a 和 b 和 c) 或不 (a 或 b 或 c)

回答by Kaz

The English sentence:

英文句子:

“if a or b or c but not all of them”

“如果 a 或 b 或 c 但不是全部”

Translates to this logic:

翻译成这个逻辑:

(a or b or c) and not (a and b and c)

The word "but" usually implies a conjunction, in other words "and". Furthermore, "all of them" translates to a conjunction of conditions: this condition, andthat condition, andother condition. The "not" inverts that entire conjunction.

“but”这个词通常意味着连词,换句话说,“and”。此外,“所有这些”转换为的条件结合:这种情况下,该条件下,其它条件。“not”反转了整个连词。

I do not agree that the accepted answer. The author neglected to apply the most straightforward interpretation to the specification, and neglected to apply De Morgan's Law to simplify the expression to fewer operators:

我不同意接受的答案。作者忽略了将最直接的解释应用到规范中,忽略了应用德摩根定律将表达式简化为更少的运算符:

 not a or not b or not c  ->  not (a and b and c)

while claiming that the answer is a "minimal form".

同时声称答案是“最小形式”。