"a 또는 b 또는 c 인 경우 모두에 대한 것은 아닙니다"에 대한 Python 구문


130

0 또는 3 개의 명령 행 인수를 수신 할 수있는 Python 스크립트가 있습니다. (기본 동작으로 실행되거나 세 개의 값을 모두 지정해야합니다.)

다음과 같은 이상적인 구문은 무엇입니까?

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

?


4
아마도`if len (sys.argv) == 0과 같은 것으로 시작할 수 있습니다 :
Edgar Aroutiounian

6
@EdgarAroutiounian len(sys.argv)은 항상 1 이상 argv[0]입니다. 실행 파일은로 포함됩니다 .
RoadieRich

10
질문의 본문이 질문의 제목과 일치하지 않습니다. "a 또는 b 또는 c이지만 전부는 아님"또는 "정확하게 a, b 및 c 중 하나 인 경우"(주어진 표현에서와 같이)를 확인 하시겠습니까?
더그 맥클린

2
a + b + c에 대해 무엇을 말할 수 있습니까?
gukoff

6
잠깐, 질문, 그것은 0 또는 3 개의 인수를 취할 수 있습니다. 그냥 if not (a and b and c)(제로 인수) 라고 말한 다음 if a and b and c(세 개의 인수 모두 ) 말할 수 없었 습니까?
acolyte

답변:


236

최소한의 형태를 의미한다면 다음과 같이하십시오.

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

질문 제목을 번역합니다.

업데이트 : Volatility and Supr에서 올바르게 말했듯이 De Morgan의 법칙을 적용하고 동등한 것을 얻을 수 있습니다.

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

내 조언은 당신과 다른 프로그래머에게 더 중요한 형식을 사용하는 것입니다. 첫 번째 수단 "거짓이 있지만 진실이 있습니다" , 두 번째 "참이 있지만 모든 것이 아닙니다"라는 의미 입니다. 하드웨어 에서이 작업을 최적화하거나 수행하려면 두 번째를 선택하십시오. 여기서 가장 읽기 쉬운 것을 선택하십시오 (테스트 할 조건과 이름도 고려하십시오). 나는 첫번째를 골랐다.


3
모든 훌륭한 답변이지만 간결한 결과로 짧은 단락으로 승리합니다. 모두 감사합니다!
Chris Wilson

38
나는 그것을 더 간결하게하고 갈 것입니다if not (a and b and c) and (a or b or c)
변동성

208
또는 if (a or b or c) and not (a and b and c)제목과 완벽하게 일치합니다.)
Supr

3
@HennyH 나는 그 질문이 "하나의 조건 만"이 아니라 "적어도 하나의 조건이 아니라 전부는 아님"을 요구한다고 믿는다.
변동성

63
@Suprif any([a,b,c]) and not all([a,b,c])
eternalmatt

238

어때요?

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

다른 변형 :

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

2
sum(conditions)2예를 들어 어떤 것이 반환되면 잘못 될 수 있습니다 True.
유미로

7
사실 당신은 못생긴 필요합니다sum(map(bool, conditions))
jamylak

5
모든 조건이 사전 평가되므로 단락되지 않습니다.
georg

14
@PaulScheltema 첫 번째 양식은 누구나 이해할 수 있습니다.
cmh

6
이 "모두가 아닌"부울 방법 중 가장 우수하고 명확한 것은 단지 arg가 존재하는 것과 arg가 'truthy'라는 중요한 차이점을 염두에 두는 것입니다.
wim

115

이 질문은 이미 많은 찬사를 받았으며 받아 들여진 대답이 많았지 만 지금까지 부울 문제를 표현하는 다양한 방법으로 혼란스러워하고 중요한 요점을 놓쳤습니다.

0 또는 3 개의 명령 행 인수를 수신 할 수있는 Python 스크립트가 있습니다. (기본 동작으로 실행되거나 지정된 세 값이 모두 필요함)

이 로직은 코드의 책임이 아니라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)

그리고 네, 그것은 선택적 인수이기 때문에 위치 인수가 아닌 옵션 이어야합니다 .


편집 : 주석에서 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)

사용 예는 다음과 같습니다.

# 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

4
예, 의도적으로 추가했습니다. 인수를 위치 적으로 지정하고 정확히 3 또는 0을 사용하도록 강제 할 수는 있지만 CLI를 적절하게 만들지 않으므로 권장하지 않습니다.
wim

8
별도의 문제. 당신은 그것이 좋은 CLI라고 믿지 않으며, 그 시점에 대해 논쟁 할 수 있으며, OP는 설득 될 수 있습니다. 그러나 귀하의 답변은 사양 변경을 언급 할만큼 충분히 질문에서 벗어납니다. 변경 사항을 언급하지 않고 사용 가능한 도구에 맞게 사양을 구부리는 것 같습니다.
LarsH

2
@LarsH 좋아, 질문에 암시 된 원래 인터페이스에 더 적합한 예제를 추가했습니다. 현재 사용 가능한 사양을 충족시키기 위해 공구를 굽히고 있습니다 ...;)
wim

2
이것이 내가 공표 한 유일한 답변입니다. 응답에 대한 +1 진짜 질문을 .
Jonathon Reinhart

1
+1. CLI의 형태는 중요한 접선 문제이며 다른 사람이 말한 것처럼 완전히 분리되지는 않습니다. 나는 당신의 게시물뿐만 아니라 다른 사람들도 찬성했습니다-당신의 문제는 근본 원인이되어 우아한 해결책을 제공하는 반면 다른 게시물은 문자적인 질문에 대답합니다. 그리고 두 종류의 답변 모두 유용하며 +1이 필요합니다.
Ben Lee

32

나는 갈 것이다 :

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

나는 이것이 상당히 효율적으로 단락되어야한다고 생각한다.

설명

conds반복자 를 만들면 , anywill 의 첫 번째 사용 은 단락되고 어떤 항목이 참이면 반복자가 다음 요소를 가리키게합니다. 그렇지 않으면 전체 목록을 소비하고입니다 False. 다음 any은 iterable의 나머지 항목을 가져 와서 다른 실제 값이 없는지 확인합니다.있는 경우 전체 문이 사실이 될 수 없으므로 고유 한 요소가 없습니다 (짧은 회로 다시). 마지막 anyFalseiterable을 반환 하거나 소진합니다 True.

참고 : 위의 조건은 단일 조건 만 설정되어 있는지 확인합니다.


하나 이상의 항목이 설정되어 있지만 모든 항목이 설정되어 있지 않은지 확인하려면 다음을 사용할 수 있습니다.

not all(conds) and any(conds)

5
나는 그것을 얻지 못한다. 다음과 같이 읽습니다. 참이 아니라 참입니다. 이해하도록 도와주세요.
rGil

1
@rGil : "일부 사과는 빨간색이고 일부는 그렇지 않은 경우"와 같습니다. "일부 사과는 빨간색이지만 전부는 아닙니다"라고 말하는 것과 같습니다.
georg

2
설명이 있어도 동작을 이해할 수 없습니다 ... [a, b, c] = [True, True, False]코드가 "prints"해서는 안되지만 False예상 출력은 True?
awesoon

6
그러나 이것은 매우 영리합니다. 그러나 얼마나 많은 조건을 미리 알지 못했는지 모르지만 고정 된 알려진 조건부 목록의 경우 가독성 손실은 그만한 가치가 없습니다.
푹신한

4
이것은 단락되지 않습니다. 목록은에 전달되기 전에 완전히 구성됩니다 iter. any그리고 all목록을 게으르게 소비 할 것이지만, 당신이 도착할 때까지 목록은 이미 완전히 평가되었습니다!
icktoofay

22

영어 문장 :

“a 또는 b 또는 c 인 경우 모두 해당하지 않는 경우”

이 논리로 변환합니다 :

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

"but"라는 단어는 일반적으로 "and"라는 연결을 의미합니다. 또한, "모두" 는 조건, 즉 이 조건 해당 조건 기타 조건의 조합으로 해석됩니다 . "not"은 전체 연결을 반전시킵니다.

동의 한 답변에 동의하지 않습니다. 저자는 사양에 가장 간단한 해석을 적용하지 않았고 소수의 운영자에게 표현을 단순화하기 위해 De Morgan의 법칙을 적용하지 않았습니다.

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

답은 "최소한 형태"라고 주장하면서.


실제로, 그 형태는 최소한입니다. 그것은의 최소한의 포스 형태로 표현합니다.
Stefano Sanfilippo

10

True세 가지 조건 중 하나에 해당 하면를 반환 합니다 True. 아마도 당신이 예제 코드에서 원하는 것입니다.

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

@defuz의 답변만큼 예쁘지 않음
jamylak

10

어떻습니까 : (독특한 조건)

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

두 조건을 허용하면 그렇게 할 수 있습니다.

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

1
기록을 위해 질문은 두 가지 조건을 요구합니다. 적어도 하나, 그러나 그들 모두는 모든 일 = 또는 전부의 2
마리우스 Balčytis

IMHO 당신은 두 번째 철자를 철자로 써야합니다 1 <= bool(a) + bool(b) + bool(c) <= 2.
Monica Monica 복원

6

분명히하기 위해 논리 TRUE가 얼마나 많은 매개 변수를 기반으로 결정하고 싶습니까 (문자열 인수의 경우-비어 있지 않음)?

argsne = (1 if a else 0) + (1 if b else 0) + (1 if c else 0)

그런 다음 결정을 내 렸습니다.

if ( 0 < argsne < 3 ):
 doSth() 

이제 논리가 더 명확합니다.


5

그리고 왜 그것들을 세지 않습니까?

import sys
a = sys.argv
if len(a) = 1 :  
    # No arguments were given, the program name count as one
elif len(a) = 4 :
    # Three arguments were given
else :
    # another amount of arguments was given

5

비트 암호가 마음에 들지 않으면 하나 또는 두 개의 true 문 사이에 있으면 모두 0 < (a + b + c) < 3돌아가고 true모두 false이거나 none이면 false로 반환 됩니다.

또한 변수를 한 번만 평가할 때 함수를 사용하여 부울을 평가하면 단순화되므로 함수를 인라인으로 작성할 수 있으며 변수를 임시로 저장할 필요가 없습니다. (예 : 0 < ( a(x) + b(x) + c(x) ) < 3.)


4

이 질문에는 세 가지 인수 (a 및 b 및 c)가 모두 필요하거나 (a 또는 b 또는 c는 아님)

이것은 다음을 제공합니다.

(a 및 b 및 c) 또는 아닙니다 (a 또는 b 또는 c)


4

내가 이해하는 것처럼 3 개의 인수를받는 함수가 있지만 그렇지 않은 경우 기본 동작으로 실행됩니다. 1 개 또는 2 개의 인수가 제공 될 때 어떻게되는지 설명하지 않았으므로 단순히 기본 동작을 수행해야한다고 가정합니다. 이 경우 다음 답변이 매우 유리하다고 생각합니다.

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

그러나 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?)

참고 : " False"값이이 메소드로 전달되지 않는다고 가정합니다 .


논증의 진실 가치를 확인하는 것은 논증의 유무를 확인하는 것과 다른 문제입니다
wim

@wim 그래서 귀하의 답변에 맞게 질문을 변환하고 있습니다. argparse 모듈은 질문과 관련이 없으며 다른 가져 오기를 추가하며 OP가 argparse를 전혀 사용하지 않을 계획이라면 전혀 도움이되지 않습니다. 또한 "스크립트"가 독립형이 아니라 모듈 또는 더 큰 코드 세트 내의 함수 인 경우 이미 인수 파서가있을 수 있으며이 큰 스크립트 내의이 특정 기능은 기본 또는 사용자 정의 할 수 있습니다. OP의 정보가 제한되어 있기 때문에 방법이 어떻게 작동 해야하는지 알 수 없지만 OP가 부울을 통과하지 않는다고 가정하는 것이 안전합니다.
Inbar Rose

질문은 "제로 또는 세 개의 명령 줄 인수를받을 수있는 파이썬 스크립트가 있습니다"라고 명시 적으로 말했지만 "3 개의 인수를받는 함수가 있습니다"라고 말하지 않았습니다. argparse 모듈은 파이썬에서 명령 줄 인수를 처리하는 기본 방법이므로 질문과 관련이 있습니다. 마지막으로, 파이썬은 "배터리 포함"입니다. 해당 모듈이 표준 라이브러리의 일부일 때 "다른 가져 오기 추가"와 관련된 단점은 없습니다.
wim

@wim 질문이 명확하지 않습니다 (예를 들어 본문이 제목과 일치하지 않음). 나는 이것이 이것이 어떤 해석에 대한 올바른 대답인지 확실하지 않다고 생각합니다 .
Monica Reinstate Monica

2

조건 반복자를 사용하면 액세스 속도가 느려질 수 있습니다. 그러나 각 요소에 두 번 이상 액세스 할 필요는 없으며 항상 모든 요소를 ​​읽을 필요는 없습니다. 무한 생성기와 함께 작동하는 솔루션은 다음과 같습니다.

#!/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])

0

모든 주어진이 때 bool이다 True, 모든 감안할 때 또는 bool입니다 False...
때 그들은 모두 서로 같습니다!

그래서, 우리는 다른 평가 두 가지 요소 찾아야 bool
중 하나 이상에 있다는 것을 알 수 True및 적어도 하나를 False.

내 짧은 해결책 :

not bool(a)==bool(b)==bool(c)

AFAIK가 원인 나는 그것을 단락을 보라 a==b==c같습니다 a==b and b==c.

내 일반적인 솔루션 :

def _any_but_not_all(first, iterable): #doing dirty work
    bool_first=bool(first)
    for x in iterable:
        if bool(x) is not bool_first:
            return True
    return False

def any_but_not_all(arg, *args): #takes any amount of args convertable to bool
    return _any_but_not_all(arg, args)

def v_any_but_not_all(iterable): #takes iterable or iterator
    iterator=iter(iterable)
    return _any_but_not_all(next(iterator), iterator)

여러 iterable을 다루는 코드도 작성했지만 무의미하다고 생각하기 때문에 여기서 삭제했습니다. 그러나 여전히 여기에서 사용할 수 있습니다 .


-2

이것은 기본적으로 "일부 (모두는 아님)"기능입니다 ( any()all() 내장 기능 ).

이것은이 있어야한다는 것을 의미 False True 결과 사이의. 따라서 다음을 수행 할 수 있습니다.

some = lambda ii: frozenset(bool(i) for i in ii).issuperset((True, False))

# one way to test this is...
test = lambda iterable: (any(iterable) and (not all(iterable))) # see also http://stackoverflow.com/a/16522290/541412

# Some test cases...
assert(some(()) == False)       # all() is true, and any() is false
assert(some((False,)) == False) # any() is false
assert(some((True,)) == False)  # any() and all() are true

assert(some((False,False)) == False)
assert(some((True,True)) == False)
assert(some((True,False)) == True)
assert(some((False,True)) == True)

이 코드의 장점 중 하나는 결과 (부울) 항목을 한 번만 반복하면된다는 것입니다.

한 가지 단점은 이러한 모든 진실 표현이 항상 평가 되고 / 연산자 와 같은 단락을 수행하지 않는다는 것 입니다.orand


1
나는 이것이 불필요한 합병증이라고 생각합니다. 왜 평범한 오래된 세트가 아닌 고정 세트입니까? .issuperset길이 2 만 확인하는 대신 bool어쨌든 True 및 False 이외의 다른 것을 반환 할 수없는 이유는 무엇입니까? 왜 def를 사용하는 대신 람다 (읽기 : 익명 함수)를 이름에 할당해야합니까?
wim

1
람다 구문은 더 논리적입니다. return사용 하면 필요하기 때문에 어쨌든 길이가 같습니다 def. 나는이 솔루션의 일반성이 좋다고 생각합니다. 부울로 제한 할 필요는 없습니다. 문제는 본질적으로 "이러한 모든 요소가 내 목록에 표시되도록하는 방법"입니다. 왜 set가변성이 필요하지 않은가? 성능이 필요하지 않은 경우 더 많은 불변성이 항상 좋습니다.
야누스 트롤 슨

@JanusTroelsen 당신이 바로 목표입니다! 이것이 내가 이런 식으로 한 이유입니다. 더 쉽고 명확하게 해줍니다. 나는 파이썬을 내 코딩 방식에 적응시키는 경향이 있습니다 :-).
Abbafei

그러나 그것은 무한한 발전기에서는 작동하지 않습니다 : P 내 대답보기 :) 힌트 :tee
Janus Troelsen

@JanusTroelsen 나는 이것을 깨닫는다 :-). 실제로 다른 방법으로 (세트에서 True / False로, 메소드 매개 변수에서 iterable로), 그러나 이것이 무한 생성기와 함께 작동하지 않으며 사용자가 깨닫지 못할 수도 있음을 깨달았습니다. (아직도 iterable set method params에 대한 문서에서 언급), 적어도 이와 같이 무한 반복자를 사용하지 않는 것이 분명합니다. 나는 알고 itertools.tee있었지만 1) 나는 복사 붙여 넣기를 보증하기에 충분히 간단하고 작은 1 라이너를 찾고있었습니다. 2) 당신은 이미 그 기술을 사용하는 대답을했습니다 :-)
Abbafei
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.