파이썬에서 "someobj가 아닌 경우 :"가 "if someobj == None :"보다 나은 이유는 무엇입니까?


127

다음과 같은 몇 가지 코드 예제를 보았습니다.

if not someobj:
    #do something

그러나 왜 안하고 있는지 궁금합니다.

if someobj == None:
    #do something

차이점이 있습니까? 하나는 다른 것보다 장점이 있습니까?


13
일반적으로 '는 someObj에 아무도없는'에 바람직 'someObj에 == 없음'
아론 Maenpaa

X가 None이 아닌 경우 의사 코드는 어떻습니까? 아니면 X != None?
Charlie Parker

이 질문은 다른 것보다 더 장황하다 ... kudos ...
alamin

답변:


187

첫 번째 테스트에서 Python은 객체가 bool아직 값이 아닌 경우 값 으로 변환하려고 시도합니다 . 대략, 우리는 목표를 묻습니다 : 당신은 의미가 있습니까? 이것은 다음 알고리즘을 사용하여 수행됩니다.

  1. 객체에 __nonzero__특수한 메소드 가있는 경우 (숫자 내장 int및 및 float)이 메소드를 호출합니다. bool직접 사용되는 int값 또는 False0과 같은 경우 고려 되는 값을 리턴해야합니다 .

  2. 객체가있는 경우 그렇지 않은 경우, __len__특별한 방법을 (같은 컨테이너에 내장 된 기능을 수행 list, dict, set, tuple, 그것은 용기를 고려,이 메소드를 호출, ...) False가 (길이가 제로) 비어있는 경우.

  3. 그렇지 않은 경우, 객체는 어떤 경우에도 고려 True되지 않는 한 None고려됩니다 False.

두 번째 테스트에서는 객체와의 동등성이 비교됩니다 None. 여기서 우리는 "당신은이 다른 가치와 같은가?" 이것은 다음 알고리즘을 사용하여 수행됩니다.

  1. 객체에 __eq__메소드 가있는 경우이 메소드가 호출되고 리턴 값이 값으로 변환되어 bool의 결과를 판별하는 데 사용됩니다 if.

  2. 그렇지 않으면 객체에 __cmp__메소드가 있으면 호출됩니다. 이 함수는 int두 객체의 순서를 나타내는 ( -1if self < other, 0if self == other, +1if self > other)를 반환해야합니다 .

  3. 그렇지 않으면, 객체는 동일성에 대해 비교된다 (즉, is운영자에 의해 테스트 될 수있는 동일한 객체를 참조한다 ).

is연산자를 사용하여 가능한 또 다른 테스트가 있습니다 . 우리는 그 대상에게 "이 특별한 대상입니까?"라고 물을 것입니다.

일반적으로 숫자가 아닌 값으로 첫 번째 테스트를 사용하고 동일한 특성 (두 문자열, 두 숫자 등)의 객체를 비교할 때 동등성 테스트를 사용하고 다음과 같은 경우에만 ID를 확인하는 것이 좋습니다. 센티넬 값을 사용하여 ( Noneexemple하는 부재 필드에 대한 초기화, 또는 사용하지 않을 때하는 의미 getattr또는 __getitem__메소드).

요약하면 다음과 같습니다.

>>> class A(object):
...    def __repr__(self):
...        return 'A()'
...    def __nonzero__(self):
...        return False

>>> class B(object):
...    def __repr__(self):
...        return 'B()'
...    def __len__(self):
...        return 0

>>> class C(object):
...    def __repr__(self):
...        return 'C()'
...    def __cmp__(self, other):
...        return 0

>>> class D(object):
...    def __repr__(self):
...        return 'D()'
...    def __eq__(self, other):
...        return True

>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
...     print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
...         (repr(obj), bool(obj), obj == None, obj is None)
  '': bool(obj) -> False, obj == None -> False, obj is None -> False
  (): bool(obj) -> False, obj == None -> False, obj is None -> False
  []: bool(obj) -> False, obj == None -> False, obj is None -> False
  {}: bool(obj) -> False, obj == None -> False, obj is None -> False
   0: bool(obj) -> False, obj == None -> False, obj is None -> False
 0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
 A(): bool(obj) -> False, obj == None -> False, obj is None -> False
 B(): bool(obj) -> False, obj == None -> False, obj is None -> False
 C(): bool(obj) ->  True, obj == None ->  True, obj is None -> False
 D(): bool(obj) ->  True, obj == None ->  True, obj is None -> False
None: bool(obj) -> False, obj == None ->  True, obj is None ->  True

4
기술적으로는 정확하지만 튜플, 목록, dicts, strs, 유니 코드, int, float 등이 0이 아닌 것은 아닙니다 . 0이 아닌 사용자 정의 방법 을 사용하는 것보다 내장 유형의 진실 값을 사용하는 것이 훨씬 일반적 입니다.
ddaa

50

이것들은 실제로 모두 나쁜 습관입니다. 옛날 옛적에, None과 False를 자연스럽게 비슷한 것으로 취급하는 것은 괜찮은 것으로 간주되었습니다. 그러나 Python 2.2 이후로는 이것이 최선의 정책이 아닙니다.

첫째, if x또는 if not x일종의 테스트 를 수행 할 때 Python은 암시 적 x으로 부울 로 변환 해야합니다. bool기능에 대한 규칙 은 거짓 인 뗏목을 설명합니다. 그 밖의 모든 것은 사실입니다. x의 값이 처음부터 부울이 아니었다면,이 암묵적인 변환은 실제로 가장 명확한 방법이 아닙니다.

Python 2.2 이전에는 bool 함수가 없었으므로 덜 명확했습니다.

둘째, 실제로 테스트해서는 안됩니다 == None. is None및을 사용해야합니다 is not None.

PEP 8, Python 코드 용 스타일 안내서를 참조하십시오 .

- Comparisons to singletons like None should always be done with
  'is' or 'is not', never the equality operators.

  Also, beware of writing "if x" when you really mean "if x is not None"
  -- e.g. when testing whether a variable or argument that defaults to
  None was set to some other value.  The other value might have a type
  (such as a container) that could be false in a boolean context!

싱글 톤은 몇 개입니까? 다섯 : None, True, False, NotImplementedEllipsis. 당신이 정말로 가능성은 희박하기 때문에 사용 NotImplemented하거나 Ellipsis, 당신은 말을하지 않을 것 if x is True(단순히이 때문에 if x많은 명확), 당신은거야 오직 테스트 None.


3
두 번째 형태는 범주 적으로 나쁜 습관이 아닙니다. PEP 8은 if x를 두 번 사용할 것을 권장 합니다. 먼저 len을 사용하는 대신 시퀀스를 사용한 다음 is를 사용하는 대신 True 및 False를 사용합니다. 실제로 내가 본 모든 파이썬 코드는 x와 x가 아닌 경우를 사용합니다.
Antti Rasinen

35

때문에이 None거짓으로 간주되는 유일한 것이 아니다.

if not False:
    print "False is false."
if not 0:
    print "0 is false."
if not []:
    print "An empty list is false."
if not ():
    print "An empty tuple is false."
if not {}:
    print "An empty dict is false."
if not "":
    print "An empty string is false."

False, 0, (), [], {}그리고 ""모든 다른 None당신이 개 코드 조각은 그래서, 하지 와 같습니다.

또한 다음을 고려하십시오.

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

if object:평등 검사 가 아닙니다 . 0, (), [], None, {}, 등이 있습니다 서로 모두 다른,하지만 그들은 모두 평가 False로.

이것은 다음과 같은 단락 표현의 "마법"입니다.

foo = bar and spam or eggs

이것은 속기입니다 :

if bar:
    foo = spam
else:
    foo = eggs

당신이 정말로 작성해야하지만 :

foo = spam if bar else egg

마지막 질문에 관해서는 그것들과 같습니다.
Sylvain Defresne

""가 False이므로 둘 다 잘못되었습니다. 두 번째는 '( "",) 또는 ( "s",)'를 읽어야합니다. 어쨌든, 최신 버전의 파이썬에는 적절한 삼항 연산자가 있습니다. 이 오류가 발생하기 쉬운 핵은 사라져야합니다.
ddaa


3

당신이 묻는다면

if not spam:
    print "Sorry. No SPAM."

스팸__nonzero__ 메소드 가 호출됩니다. 파이썬 매뉴얼에서 :

__nonzero__ ( self ) 실제 값 테스트 및 내장 연산 bool ()을 구현하기 위해 호출됩니다. False 또는 True 또는 해당 정수 0 또는 1을 리턴해야합니다.이 메소드가 정의되지 않은 경우 __len __ ()이 정의 된 경우 호출됩니다 (아래 참조). 클래스가 __len __ () 또는 __nonzero __ ()을 정의하지 않으면 모든 인스턴스가 true로 간주됩니다.

당신이 묻는다면

if spam == None:
    print "Sorry. No SPAM here either."

스팸__eq__ 메소드는 None 인수와 함께 호출됩니다 .

사용자 정의 가능성에 대한 자세한 내용은 https://docs.python.org/reference/datamodel.html#basic-customization 에서 Python 문서를 참조하십시오.


2

이 두 비교는 다른 목적으로 사용됩니다. 전자는 무언가의 부울 값을 확인하고 두 번째는 None 값을 가진 동일성을 확인합니다.


1
절대적으로 정확하기 위해 두 번째는 None 값으로 -equality-를 확인합니다 ... "someobj is None"은 ID를 확인합니다.
Matthew Trevor

0

하나의 첫 번째 예는 더 짧고 멋지게 보입니다. 다른 게시물에 따라 선택하는 내용은 실제로 비교로 수행하려는 작업에 따라 다릅니다.


0

대답은 "그것은 달려있다"입니다.

이 컨텍스트에서 0, "", [] 및 False (전체가 아님)를 None과 동일하다고 생각하면 첫 번째 예제를 사용합니다.


0

개인적으로 나는 여러 언어에 걸쳐 일관된 접근 방식을 선택했습니다. if (var)var가 부울로 선언 된 경우에만 (또는 C에서 특정 유형이없는 경우에만) 동등한 작업을 수행합니다. 나는 실수로 다른 유형을 여기에서 사용하지 않도록하기 위해 이러한 변수 앞에 접두사를 붙입니다 b( bVar실제로 그렇습니다 ).
수많은 복잡한 규칙이있을 때 부울에 대한 암시 적 캐스팅을 좋아하지 않습니다.

물론 사람들은 동의하지 않을 것입니다. 일부는 더 멀리 가고, 나는 if (bVar == true)내 작업에서 Java 코드에서 볼 수 있습니다 (내 취향에 너무 중복되어 있습니다!), 다른 일부는 너무 간결한 구문을 좋아합니다 while (line = getNextLine()).

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