파이썬에서 표현식 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).

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

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


이러한 비교 중 일부를 시도하고 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. 비교 연산자를 함께 연결할 수 있으며 쌍 연산자로 자동 확장됩니다.


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

파이썬에서 TrueFalse단지 인스턴스 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 < 00 == 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!=yx<>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.