파이썬에서 표현식 0 <0 == 0이 False를 반환하는 이유는 무엇입니까?


136

Python 2.6에서 Queue.py를 살펴보면이 구성이 조금 이상하다는 것을 알았습니다.

def full(self):
    """Return True if the queue is full, False otherwise
    (not reliable!)."""
    self.mutex.acquire()
    n = 0 < self.maxsize == self._qsize()
    self.mutex.release()
    return n

경우 maxsize0 큐는 결코 가득 차있다.

내 질문은이 경우 어떻게 작동합니까? 0 < 0 == 0거짓으로 어떻게 간주됩니까?

>>> 0 < 0 == 0
False
>>> (0) < (0 == 0)
True
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True

파이썬에서 0 <True가 False와 동일합니까?
— 마리노 시미치

3
@Marino Šimić : OP의 질문에 표시된 두 번째 예에서 >>> (0) < (0 == 0)분명히 그렇지 않습니다.
— martineau

3
n = 0 < self.maxsize == self._qsize()어떤 언어로든 코드를 작성하지 않아야하는 한 가지 이유 입니다. 무슨 일이 일어나고 있는지 알아 내기 위해 눈을 여러 번 앞뒤로 다트어야한다면 잘 쓰여진 선이 아닙니다. 여러 줄로 나누면됩니다.
— BlueRaja-대니 Pflughoeft

2
@ Blue : 나는 그런 비교를 그런 식으로 쓰지 않지만 별도의 줄로 나누는 것은 두 번의 비교를 위해 약간 넘어져 가고 있다는 것에 동의합니다. 나는 당신이 그것을 별도의 비교로 나누기를 바랍니다. ;)
— Jeff Mercado

2
@ Blue : 쓰지 않았습니다 .Python 2.6에 있습니다. 나는 무슨 일이 일어나고 있는지 이해하려고 노력했습니다.
— Marcelo Santos

답변:


113

파이썬에는 범위 비교를 쉽게 표현할 수 있도록 일련의 관계 연산자에 대한 특별한 경우 처리 기능이 있다고 생각합니다. 말하는 0 < x <= 5것보다 말할 수있는 것이 훨씬 좋습니다 (0 < x) and (x <= 5).

이를 체인 비교 라고 합니다. 그리고 그것은 그것들을위한 문서에 대한 링크입니다.

당신이 이야기하는 다른 경우들에서, 괄호는 하나의 관계 연산자가 다른 관계 연산자보다 먼저 적용되도록하므로 더 이상 연쇄 비교되지 않습니다. 그리고 이후 True및 False정수로 값을 당신은 괄호 버전 밖으로 수행 답변을 얻을.


이러한 비교 중 일부를 시도하고 int () 및 bool ()을 지정하는 것이 흥미 롭습니다. 나는 0이 아닌의 BOOL이 () 나는 심지어 직접 사고 실험 전에 부울 (0) 또는 부울 (1) 이외의 지정에 시도하지 못했네 1. 추측 것을 깨달았다
— j_syk

대신이 섹션에 연결 하시겠습니까? docs.python.org/2/reference/expressions.html#comparisons
— tavnab

@tavnab-그렇습니다. 나는 그것을 고치는 것을 기억하려고 노력할 것이다. 편집 내역도 확인하겠습니다. 그것은 내가 저지르는 실수처럼 보이지 않습니다. 😕
— 전능 한

42

때문에

(0 < 0) and (0 == 0)

입니다 False. 비교 연산자를 함께 연결할 수 있으며 쌍 연산자로 자동 확장됩니다.


편집-파이썬에서 참과 거짓에 대한 설명

파이썬에서 True와 False단지 인스턴스 bool의 서브 클래스입니다 int. 다시 말해, True실제로는 1입니다.

요점은 정수와 똑같이 부울 비교 결과를 사용할 수 있다는 것입니다. 이것은 다음과 같은 혼란을 초래합니다

>>> (1==1)+(1==1)
2
>>> (2<1)<1
True

그러나 이러한 평가는 비교를 괄호로 묶어 먼저 평가되도록하는 경우에만 발생합니다. 그렇지 않으면 파이썬은 비교 연산자를 확장합니다.


2
어제 정수로 사용되는 부울 값에 대한 흥미로운 사용법을 보았습니다. 표현식 'success' if result_code == 0 else 'failure'을로 다시 작성할 수 있습니다. ('error', 'success')[result_code == 0]이 전에 목록 / 튜플에서 항목을 선택하는 데 사용되는 부울을 본 적이 없었습니다.
— Andrew Clark

'bool'은 Python 2.2 주위에 언젠가 추가되었습니다.
— MRAB

18

이상한 행동은 파이썬이 조건을 연쇄시키는 능력에서 비롯됩니다. 0이 0보다 작지 않다는 것을 알기 때문에 전체 표현식이 false로 평가됩니다. 이를 별도의 조건으로 나누 자마자 기능이 변경됩니다. 처음 a < b && b == c에의 원래 진술 을 위해 기본적으로 테스트하고 있습니다 a < b == c.

다른 예시:

>>> 1 < 5 < 3
False

>>> (1 < 5) < 3
True

1
OMG, OO a < b && b == c와 동일a < b == c
— Kiril Kirov

9
>>> 0 < 0 == 0
False

이것은 체인 비교입니다. 각 쌍별 비교가 차례로 참이면 true를 리턴합니다. 그것은(0 < 0) and (0 == 0)

>>> (0) < (0 == 0)
True

이것은 0 < TrueTrue로 평가되는 것과 같습니다 .

>>> (0 < 0) == 0
True

이것은 False == 0True로 평가되는 것과 같습니다 .

>>> 0 < (0 == 0)
True

0 < True위와 같이 True로 평가되는 것과 같습니다 .


7

이유는 분명합니다 (이 코드 바이트) 분해에서 찾고 0 < 0 == 0있다 False.

이 표현에 대한 분석은 다음과 같습니다.

>>>import dis

>>>def f():
...    0 < 0 == 0

>>>dis.dis(f)
  2      0 LOAD_CONST               1 (0)
         3 LOAD_CONST               1 (0)
         6 DUP_TOP
         7 ROT_THREE
         8 COMPARE_OP               0 (<)
        11 JUMP_IF_FALSE_OR_POP    23
        14 LOAD_CONST               1 (0)
        17 COMPARE_OP               2 (==)
        20 JUMP_FORWARD             2 (to 25)
   >>   23 ROT_TWO
        24 POP_TOP
   >>   25 POP_TOP
        26 LOAD_CONST               0 (None)
        29 RETURN_VALUE

통지 라인 0-8 :이 라인 은 파이썬 스택으로 0 < 0분명히 리턴 되는지 확인합니다 False.

이제 11 행에 주목하십시오. JUMP_IF_FALSE_OR_POP 23 즉, 0 < 0반환 False할 경우 23 행으로 이동합니다.

이제 0 < 0되어 False있기 때문에 점프와 스택을 잎하는 수행 한 False전체 표현식의 반환 값 인 0 < 0 == 0짝수 불구하고, == 0일부는 심지어 확인되지 않습니다.

결론적으로, 그 대답은이 질문에 대한 다른 대답에서 말한 것과 같습니다. 0 < 0 == 0특별한 의미가 있습니다. 컴파일러는 두 가지 측면이 평가 : 0 < 0와 0 == 0. 그 and사이에 있는 복잡한 부울 식과 마찬가지로 첫 번째가 실패하면 두 번째 표현식 도 검사되지 않습니다.

희망이 이것에 약간의 영향을 미치며,이 예상치 못한 행동을 분석하는 데 사용한 방법이 다른 사람들이 앞으로도 같은 시도를하도록 격려하기를 정말로 바랍니다.


특정 구현을 리버스 엔지니어링하는 것보다 사양에서 해결하는 것이 더 쉽지 않습니까?
— David Heffernan

아니요. 짧은 대답입니다. 나는 그것이 당신의 성격에 달려 있다고 생각합니다. "블랙 박스"보기와 관련하여 사양 및 문서에서 답변을 얻는 것을 선호하는 경우이 답변은 혼란을 줄 것입니다. 물건의 내부를 파고 공개하고 싶다면이 대답은 당신을위한 것입니다. 이 리버스 엔지니어링은 하나의 특정 구현에만 관련되어 있으며 지적해야하지만 귀하의 지적은 아니지만이 답변의 요점은 아닙니다. 파이썬에서 궁금한 사람들을 위해 "후면에서"한 눈에 보는 것이 얼마나 쉬운지를 보여줍니다.
— SatA

1
리버스 엔지니어링의 문제점은 예측력이 없다는 것입니다. 새로운 언어를 배우는 방법이 아닙니다.
— David Heffernan

추가해야 할 또 다른 사항은 사양과 설명서가 항상 완전한 것은 아니며 대부분의 경우 이러한 특정 사례에 대한 답변을 제공하지 않는다는 것입니다. 그런 다음 답을 얻는 데 필요한만큼 탐구하고 조사하며 더 깊이 도달하는 것을 두려워해서는 안됩니다.
— SatA

2

다른 사람들이 언급했듯이 y는 한 번만 평가된다는 보너스와 함께 x comparison_operator y comparison_operator z구문 설탕입니다 (x comparison_operator y) and (y comparison_operator z).

따라서 당신의 표현 0 < 0 == 0은 실제로 어느 것이 정당한지 (0 < 0) and (0 == 0)평가합니다 .False and TrueFalse


2

아마도이 문서 에서 발췌 한이 도움이 될 수 있습니다.

이것들은 소위“풍부한 비교”방법이며 __cmp__()아래 에 우선하는 비교 연산자를 위해 요구 됩니다. 다음 조작 기호와 메소드 명 간의 대응 관계는 다음과 x<y통화 x.__lt__(y), x<=y통화 x.__le__(y), x==y통화 x.__eq__(y), x!=y및 x<>y 통화 x.__ne__(y), x>y통화 x.__gt__(y)및 x>=y통화 x.__ge__(y).

리치 비교 메소드는 NotImplemented주어진 인수 쌍에 대해 연산을 구현하지 않으면 싱글 톤을 리턴 할 수 있습니다 . 관례 적으로, False그리고 True성공적인 비교를 위해 반환됩니다. 그러나 이러한 메소드는 모든 값을 반환 할 수 있으므로 비교 연산자가 부울 컨텍스트 (예 : if 문의 조건)에서 사용되는 경우 Python은 bool()값을 호출 하여 결과가 참인지 거짓인지 확인합니다.

비교 연산자 사이에는 내재 된 관계가 없습니다. 진실은 x==y그것이 x!=y 거짓 임을 암시하지 않습니다 . 따라서을 정의 할 때 연산자가 예상대로 작동하도록 __eq__()정의 __ne__()해야합니다. __hash__()사용자 정의 비교 연산을 지원하고 사전 키로 사용할 수있는 해시 가능 객체 생성 에 대한 중요한 참고 사항 은 단락을 참조하십시오 .

이러한 메소드의 교환 된 인수 버전은 없습니다 (왼쪽 인수는 연산을 지원하지 않지만 오른쪽 인수는 지원합니다). 오히려, __lt__()그리고 __gt__() 서로의 반영이다, __le__() 그리고 __ge__()서로의 반사하고, __eq__()그리고 __ne__() 자신의 반영이다.

풍부한 비교 방법에 대한 주장은 결코 강요되지 않습니다.

이것들은 비교이지만 체인 비교 이므로 다음을 알아야합니다.

비교는 임의로 연결될 수 있습니다. 예를 들어, y는 한 번만 평가된다는 점을 제외하고 x < y <= z는 동일합니다 x < y and y <= z(그러나 두 경우 모두 x <y가 거짓 인 경우 z는 전혀 평가되지 않습니다).

공식적으로 a, b, c, ..., y, z가 표현식이고 op1, op2, ..., opN이 비교 연산자 인 경우 op1 b op2 c ... y opN z는 op1 b와 같습니다. 및 b op2 c 및 ... y opN z (각식이 최대 한 번 평가되는 것을 제외하고).


1

여기에 모든 영광이 있습니다.

>>> class showme(object):
...   def __init__(self, name, value):
...     self.name, self.value = name, value
...   def __repr__(self):
...     return "<showme %s:%s>" % (self.name, self.value)
...   def __cmp__(self, other):
...     print "cmp(%r, %r)" % (self, other)
...     if type(other) == showme:
...       return cmp(self.value, other.value)
...     else:
...       return cmp(self.value, other)
... 
>>> showme(1,0) < showme(2,0) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
False
>>> (showme(1,0) < showme(2,0)) == showme(3,0)
cmp(<showme 1:0>, <showme 2:0>)
cmp(<showme 3:0>, False)
True
>>> showme(1,0) < (showme(2,0) == showme(3,0))
cmp(<showme 2:0>, <showme 3:0>)
cmp(<showme 1:0>, True)
True
>>> 

0

나는 파이썬이 마술 사이에서 이상한 일을하고 있다고 생각합니다. 동일 1 < 2 < 3방법 2는 1과 3 사이에있다.

이 경우에는 [중간 0]이 [왼쪽 0]보다 크고 [오른쪽 0]과 같습니다. 중간 0은 왼쪽 0보다 크지 않으므로 false로 평가됩니다.

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