"and"및 "or"는 부울이 아닌 값으로 어떻게 작동합니까?


99

나는 파이썬을 배우려고 노력하고 있는데 멋지고 짧지 만 완전히 말이되지 않는 코드를 발견했습니다.

컨텍스트는 다음과 같습니다.

def fn(*args):
    return len(args) and max(args)-min(args)

나는 그것이 무엇을하고 있는지 알지만 왜 파이썬이 이것을 수행합니까-즉 True / False 대신 값을 반환합니까?

10 and 7-2

5를 반환합니다. 마찬가지로 및를 또는로 변경하면 기능이 변경됩니다. 그래서

10 or 7 - 2

10을 반환합니다.

이 합법적이고 신뢰할 수있는 스타일입니까, 아니면 이에 대한 문제가 있습니까?


1
and(뿐만 아니라 or)은 부울 값으로 작업하거나 반환하는 데 제한되지 않습니다.
cs95

1
IMNSHO : 그것은 그것을 쓰는 다소 혼란스러운 방법입니다. 부울 (구분 된 최소값과 최대 값) 또는 숫자 (최소값과 최대 값의 차이)를 반환해야하는지 쉽게 알 수 없습니다. 후자의 경우 길이가 0 인 목록의 차이를 숫자로 제공하는 것이 합리적 일지에 대한 질문도 있습니다. (대신 None또는 예외)
일까 추

7
다른 사람들이 설명했듯이 작동하지만 한 가지 가능한 문제는 그것이 반환되면 비어 0있는지 args비어 있지 않은지 알 수 없지만 모든 요소가 동일하다는 것입니다.
특히 라임

@EspeciallyLime : 정확합니다. 나는 내 대답 에서 그것을 언급했습니다 .
Eric Duminil

답변:


135

TL; DR

두 논리 연산자 and및 의 두 동작을 요약하여 시작합니다 or. 이러한 관용구는 아래 논의의 기초가 될 것입니다.

and

첫 번째 Falsy 값이 있으면 반환하고, 그렇지 않으면 표현식의 마지막 값을 반환합니다.

or

첫 번째 Truthy 값이 있으면 반환하고, 그렇지 않으면 식의 마지막 값을 반환합니다.

동작은 문서 , 특히이 표에 요약되어 있습니다 .

여기에 이미지 설명 입력

피연산자에 관계없이 부울 값을 반환하는 유일한 연산자는 not연산자입니다.


"진실성"및 "진실성"평가

진술

len(args) and max(args) - min(args)

A는 매우 파이썬 간결 (틀림없이 적은 읽기) "하면 말하는 방법 args비어 있지의 결과를 반환 max(args) - min(args)그렇지 않으면 반환"는 0. 일반적으로 표현을보다 간결하게 표현한 것입니다 if-else. 예를 들면

exp1 and exp2

(대략) 번역해야합니다 :

r1 = exp1
if r1:
    r1 = exp2

또는 동등하게

r1 = exp1 if exp1 else exp2

비슷하게,

exp1 or exp2

다음과 같습니다.

r1 = exp1
if not r1:
    r1 = exp2

어디 exp1exp2일부 개체를 반환 임의의 파이썬 객체, 또는 표현입니다. 여기 에서 논리 연산자 andor연산자 의 사용을 이해하는 데있어 핵심 은 부울 값을 연산하거나 반환하는 데 제한되지 않는다는 것을 이해하는 것입니다. 진실성 값을 가진 모든 개체를 여기서 테스트 할 수 있습니다. 여기에는 int, str, list, dict, tuple, set, NoneType, 및 사용자 객체를 정의했다. 단락 규칙도 여전히 적용됩니다.

그러나 진실이란 무엇입니까?
조건식에서 사용될 때 객체가 평가되는 방식을 나타냅니다. @Patrick Haugh는 이 게시물 에서 진실성을 멋지게 요약 합니다.

"허위"인 다음을 제외하고 모든 값은 "진정한"것으로 간주됩니다.

  • None
  • False
  • 0
  • 0.0
  • 0j
  • Decimal(0)
  • Fraction(0, 1)
  • [] -빈 list
  • {} -빈 dict
  • () -빈 tuple
  • '' -빈 str
  • b'' -빈 bytes
  • set() -빈 set
  • range처럼,range(0)
  • 대상
    • obj.__bool__() 보고 False
    • obj.__len__() 보고 0

"truthy"값은 if또는 while 문에 의해 수행 된 검사를 충족합니다 . 우리는 차별화에 "truthy"와 "falsy을"사용 bool가치 TrueFalse.


어떻게 and작동

우리는 이러한 경우에 이러한 연산자가 어떻게 작동하는지에 대한 토론의 후속으로 OP의 질문을 기반으로합니다.

정의가있는 함수가 주어짐

def foo(*args):
    ...

0 개 이상의 인수 목록에서 최소값과 최대 값의 차이를 어떻게 반환합니까?

최소값과 최대 값을 찾는 것은 쉽습니다 (내장 함수 사용!). 여기서 유일한 문제는 인수 목록이 비어있을 수있는 코너 케이스를 적절하게 처리하는 것입니다 (예 : 호출 foo()). and연산자 덕분에 한 줄로 두 가지를 모두 수행 할 수 있습니다 .

def foo(*args):
     return len(args) and max(args) - min(args)

foo(1, 2, 3, 4, 5)
# 4

foo()
# 0

and이 사용 되므로 첫 번째 표현식이 인 경우 두 번째 표현식도 평가되어야합니다 True. 첫 번째 표현식이 진실로 평가되면 반환 값은 항상 두 번째 표현식 의 결과입니다 . 첫 번째 표현식이 Falsy로 평가되면 반환 된 결과는 첫 번째 표현식의 결과입니다.

위의 함수에서 foo하나 이상의 인수를받는 경우 는 (양수) len(args)보다 크므 0로 반환 된 결과는입니다 max(args) - min(args). 인수가 전달되지 않은 경우 OTOH, len(args)이다 0Falsy하고, 어떤 0반환됩니다.

이 함수를 작성하는 다른 방법은 다음과 같습니다.

def foo(*args):
    if not len(args):
        return 0

    return max(args) - min(args)

또는 더 간결하게

def foo(*args):
    return 0 if not args else max(args) - min(args)

물론, 이러한 함수 중 어떤 것도 유형 검사를 수행 하지 않으므로 제공된 입력을 완전히 신뢰 하지 않는 한 이러한 구성의 단순성에 의존 하지 마십시오 .


어떻게 or작동

or인위적인 예를 들어 비슷한 방식으로 작업을 설명합니다 .

정의가있는 함수가 주어짐

def foo(*args):
    ...

foo모든 숫자를 반환 하려면 어떻게 완료 9000하시겠습니까?

or여기서 코너 케이스를 처리하는 데 사용 합니다. 우리는 다음 foo과 같이 정의 합니다.

def foo(*args):
     return [x for x in args if x > 9000] or 'No number over 9000!'

foo(9004, 1, 2, 500)
# [9004]

foo(1, 2, 3, 4)
# 'No number over 9000!'

foo목록에서 필터링을 수행하여 모든 숫자를 유지합니다 9000. 그러한 숫자가 있으면 목록 이해의 결과는 Truthy 인 비어 있지 않은 목록이되므로 반환됩니다 (여기에서 작동중인 단락). 그러한 숫자가 없으면 목록 comp의 결과 []는 Falsy입니다. 이제 두 번째 표현식이 평가되고 (비어 있지 않은 문자열) 반환됩니다.

조건문을 사용하여이 함수를 다음과 같이 다시 작성할 수 있습니다.

def foo(*args):
    r = [x for x in args if x > 9000]
    if not r:
        return 'No number over 9000!' 

    return r

이전과 마찬가지로이 구조는 오류 처리 측면에서 더 유연합니다.


33
간결함을 위해 모든 명확성을 희생하는 것은 "파이썬"이 아닙니다. 제 생각에는 여기에 해당됩니다. 이것은 간단한 구조가 아닙니다.
DBedrenko

11
파이썬 조건식이이 구문을 덜 일반적으로 만들었습니다. 나는 확실히 max (args)-min (args) if len (args) 그렇지 않으면 0을 원본보다 선호합니다.
richardb

3
처음에 혼동되는 또 다른 일반적인 것은 존재하지 않는 경우 값을 할당하는 것입니다. "some_var = arg or 3"
Erik

12
@Baldrickk 사람들이 삼항 연산자를 선호하기 위해이 구문을 강타하기 전에, n 항 조건식에 관해서는 삼항 연산자가 빨리 벗어날 수 있음을 명심하십시오. 예를 들어, if ... else (if ... else (if ... else (if ... else ...)))다시 작성할 수 있으며 ... and ... and ... and ... and ...그 시점에서 두 경우 모두 가독성을 주장하기가 정말 어려워집니다.
cs95

4
간결함을 위해 명확성을 희생하는 것은 비단뱀이 아니지만 그렇게하지 않습니다. 잘 알려진 관용구입니다. 다른 관용구와 마찬가지로 배워야하는 관용구이지만 '명확성을 희생하는 것'은 아닙니다.
Miles Rout

18

Python 문서 에서 인용

어느 쪽도 있음을 참고 and하거나하는 것은 or 제한하지 값을 하고 입력 그들은으로 되돌아 FalseTrue, 오히려 돌아 마지막에 평가 인수를 . 이것은 때로 유용합니다. 예를 들어, s비어있는 경우 기본값으로 대체해야하는 문자열 인 경우 표현식 s or 'foo'이 원하는 값을 생성합니다.

그래서 이것은 파이썬이 부울 표현식을 평가하도록 설계된 방법이며 위의 문서는 그들이 왜 그렇게했는지에 대한 통찰력을 제공합니다.

부울 값을 얻으려면 그냥 형변환하십시오.

return bool(len(args) and max(args)-min(args))

왜?

단락.

예를 들면 :

2 and 3 # Returns 3 because 2 is Truthy so it has to check 3 too
0 and 3 # Returns 0 because 0 is Falsey and there's no need to check 3 at all

같은 경우 or도 마찬가지입니다. 즉, Truthy 라는 표현식을 찾으면 즉시 반환 하므로 나머지 표현식을 평가하는 것은 중복됩니다.

대신 하드 코어를 반환 True하거나 False, 파이썬 반환 Truthy 또는 Falsey은 , 어쨌든로 평가하려고하는 TrueFalse. 표현식을 그대로 사용할 수 있으며 여전히 작동합니다.


TruthyFalsey 가 무엇인지 알아 보려면 Patrick Haugh의 답변을 확인하십시오.


7

또는 부울 논리를 수행하지만 비교할 때 실제 값 중 하나를 반환합니다. 사용할 때 왼쪽에서 오른쪽으로, 값은 부울 문맥에서 평가된다. 0, '', [], (), {}None 은 부울 컨텍스트에서 false입니다. 다른 모든 것은 사실입니다.

모든 값은 부울 컨텍스트에 해당하는, 경우 마지막 값을 반환합니다.

>>> 2 and 5
5
>>> 2 and 5 and 10
10

값은 부울 컨텍스트에서 false 인 경우 첫 거짓 값을 반환합니다.

>>> '' and 5
''
>>> 2 and 0 and 5
0

그래서 코드

return len(args) and max(args)-min(args)

인수가max(args)-min(args) 있을 때 의 값을 반환하고 그렇지 않으면 0 인 값을 반환합니다 .len(args)


5

이 합법적이고 신뢰할 수있는 스타일입니까, 아니면 이에 대한 문제가 있습니까?

이것은 합법적이며 마지막 값이 반환되는 단락 평가 입니다.

좋은 예를 제공합니다. 0인수가 전달되지 않으면 함수가 반환 되며 코드는 전달 된 인수가없는 특별한 경우를 확인할 필요가 없습니다.

이것을 사용하는 또 다른 방법은 빈 목록과 같이 변경 가능한 기본 요소에 None 인수를 기본값으로 설정하는 것입니다.

def fn(alist=None):
    alist = alist or []
    ....

참이 아닌 값이 alist기본적으로 빈 목록으로 전달 되면 if명령문과 변경 가능한 기본 인수 함정 을 피하는 편리한 방법


3

Gotchas

예, 몇 가지 문제가 있습니다.

fn() == fn(3) == fn(4, 4)

첫째, fnreturns 0이면 매개 변수없이, 하나의 매개 변수와 함께 또는 여러 개의 동일한 매개 변수를 사용하여 호출되었는지 알 수 없습니다.

>>> fn()
0
>>> fn(3)
0
>>> fn(3, 3, 3)
0

무슨 fn뜻이야?

그렇다면 Python은 동적 언어입니다. fn무엇을하는지, 입력이 무엇인지, 출력이 어떻게 보일지 어디에도 지정되어 있지 않습니다 . 따라서 함수 이름을 올바르게 지정하는 것이 정말 중요합니다. 마찬가지로 인수를 호출 할 필요는 없습니다 args. delta(*numbers)또는 calculate_range(*numbers)함수가 수행해야하는 작업을 더 잘 설명 할 수 있습니다.

인수 오류

마지막으로 논리 and연산자는 인수없이 호출 될 경우 함수가 실패하는 것을 방지해야합니다. 그러나 일부 인수가 숫자가 아니면 여전히 실패합니다.

>>> fn('1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> fn(1, '2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
TypeError: '>' not supported between instances of 'str' and 'int'
>>> fn('a', 'b')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn
TypeError: unsupported operand type(s) for -: 'str' and 'str'

가능한 대안

"허가보다 용서를 구하기가 더 쉽다" 에 따라 함수를 작성하는 방법이 있습니다. 원리 :

def delta(*numbers):
    try:
        return max(numbers) - min(numbers)
    except TypeError:
        raise ValueError("delta should only be called with numerical arguments") from None
    except ValueError:
        raise ValueError("delta should be called with at least one numerical argument") from None

예로서:

>>> delta()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in delta
ValueError: delta should be called with at least one numerical argument
>>> delta(3)
0
>>> delta('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 'b')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta('a', 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in delta
ValueError: delta should only be called with numerical arguments
>>> delta(3, 4.5)
1.5
>>> delta(3, 5, 7, 2)
5

delta인수없이가 호출 될 때 예외를 발생시키고 싶지 않다면, 그렇지 않으면 불가능한 값을 반환 할 수 있습니다 (예 : -1또는 None) :

>>> def delta(*numbers):
...     try:
...         return max(numbers) - min(numbers)
...     except TypeError:
...         raise ValueError("delta should only be called with numerical arguments") from None
...     except ValueError:
...         return -1 # or None
... 
>>> 
>>> delta()
-1

0

이 합법적이고 신뢰할 수있는 스타일입니까, 아니면 이에 대한 문제가 있습니까?

이 질문에 합법적이고 신뢰할 수있을뿐만 아니라 매우 실용적이라고 덧붙이고 싶습니다. 다음은 간단한 예입니다.

>>>example_list = []
>>>print example_list or 'empty list'
empty list

따라서 실제로 유리하게 사용할 수 있습니다. 간결하게하기 위해 이것이 내가 보는 방법입니다.

Or 운영자

Python의 or연산자는 첫 번째 Truth-y 값 또는 마지막 값을 반환하고 중지합니다.

And 운영자

Python의 and연산자는 첫 번째 False-y 값 또는 마지막 값을 반환하고 중지합니다.

무대 뒤에서

파이썬에서는 True0 을 제외한 모든 숫자가 해석 됩니다. 따라서 다음과 같이 말합니다.

0 and 10 

와 같다:

False and True

어느 것이 분명 False합니다. 따라서 0을 반환하는 것이 논리적입니다.


0

예. 이것은 올바른 동작과 비교입니다.

파이썬에서 적어도 A and B반환 B하는 경우 A기본적으로되어 True있는 경우를 포함하여 ANOT NULL, NOT이다 NoneNOT (예 : 빈으로 빈 용기 list, dict등). AIFF A는 본질적으로 False또는 None또는 비어 있거나 Null입니다.

반면에, A or B반환 A하는 경우 A기본적으로되어 True있는 경우를 포함하여 A, NOT NULL 인 NOT None(예 : 빈 등 NOT 빈 용기 list, dict등) 그렇지 않으면 반환 B.

파이썬에서 non-null비어 있지 않은 객체가 True로 평가되면 부울처럼 취급 되기 때문에이 동작을 눈치 채지 못하거나 간과하기 쉽습니다 .

예를 들어, 다음은 모두 "True"를 인쇄합니다.

if [102]: 
    print "True"
else: 
    print "False"

if "anything that is not empty or None": 
    print "True"
else: 
    print "False"

if {1, 2, 3}: 
    print "True"
else: 
    print "False"

반면에 다음은 모두 "False"를 인쇄합니다.

if []: 
    print "True"
else: 
    print "False"

if "": 
    print "True"
else: 
    print "False"

if set ([]): 
    print "True"
else: 
    print "False"

감사합니다. 내가 쓰고 싶었던 A것은 본질적으로 True. 수정되었습니다.
emmanuelsa

0

간단하게 이해하려면

그리고 : if first_val is False return first_val else second_value

예 :

1 and 2 # here it will return 2 because 1 is not False

그러나,

0 and 2 # will return 0 because first value is 0 i.e False

그리고 => 누군가가 거짓이면 거짓입니다. 둘 다 사실이라면 그것은 사실이 될 것입니다

또는 : if first_val is False return second_val else first_value

이유는 first가 false이면 2가 true인지 아닌지 확인하기 때문입니다.

예 :

1 or 2 # here it will return 1 because 1 is not False

그러나,

0 or 2 # will return 2 because first value is 0 i.e False

또는 => 누군가가 거짓이면 참이됩니다. 따라서 첫 번째 값이 거짓이면 2 값이 무엇이든 상관 없습니다. 그래서 그것은 그것이 될 수있는 두 번째 값을 반환합니다.

누군가가 사실이라면 그것은 사실이 될 것입니다. 둘 다 거짓이면 거짓이됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.