为什么在Python中“如果不是someobj:”比“if someobj == None:”更好?

我已经看到了几个这样的代码的例子:

if not someobj:
    #do something

但我想知道为什么不这样做:

if someobj == None:
    #do something

有什么区别吗? 一个人比另一个人有优势吗?


在第一个测试中,Python尝试将对象转换为一个bool值,如果它不是一个。 粗略地说, 我们在问这个对象:你是否有意义? 这是使用以下算法完成的:

  • 如果对象有一个__nonzero__特殊方法(就像数字内置, intfloat ),它会调用这个方法。 它必须返回一个直接使用的bool值,或者返回一个如果等于零则认为是Falseint值。

  • 否则,如果对象有一个__len__特殊方法(就像容器内置函数, listdictsettuple等一样),它会调用这个方法,如果容器为空(长度为零)则考虑容器False

  • 否则,该对象被认为是True除非它是None在这种情况下,它被认为是False

  • 在第二个测试中,对象与None进行比较。 在这里, 我们问这个对象,“你是否等于这个其他的价值?” 这是使用以下算法完成的:

  • 如果该对象有一个__eq__方法,则调用该方法,然后将返回值转换为bool值并用于确定if的结果。

  • 否则,如果该对象具有__cmp__方法,则会调用该方法。 这个函数必须返回一个int值来表示两个对象的顺序(如果self < other ,则为-1 ,如果self == other则为0 ,如果self > other +1 )。

  • 否则,对象的身份进行比较(即它们引用的是同一个对象,可以由is运算符测试)。

  • 使用is运算符还有另一个可能的测试。 我们会问这个对象,“你是这个特定对象吗?”

    一般来说,我会建议使用非数值的第一个测试,当您想比较相同性质的对象(两个字符串,两个数字,...)时使用测试来判断是否相等,使用sentinel值( None意味着没有为成员字段初始化,例如使用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
    

    这些实际上都是不好的做法。 曾几何时,认为随便把None和False视为相似是可以的。 但是,从Python 2.2开始,这不是最好的策略。

    首先,当你做一个if x或者if not x类型的测试时,Python必须将x隐式转换为布尔值。 bool函数的规则描述了大量的False事件; 其他一切都是真的。 如果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!
    

    有多少个单身人士? 五: NoneTrueFalseNotImplementedEllipsis 。 既然你不太可能使用NotImplemented或者Ellipsis ,并且你永远不会说if x is True (因为if x更清晰),你将只能测试None


    因为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."
    

    False0()[]{}""都与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
    
    链接地址: http://www.djcxy.com/p/31685.html

    上一篇: Why is "if not someobj:" better than "if someobj == None:" in Python?

    下一篇: Swift vs Kotlin performance on sorting array