为什么在python中”if not someobj:”比”if someobj==none:”更好?

Why is “if not someobj:” better than “if someobj == None:” in Python?

我看到过一些这样的代码示例:

1
2
if not someobj:
    #do something

但我想知道为什么不做:

1
2
if someobj == None:
    #do something

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


在第一个测试中,python尝试将对象转换为一个bool值(如果它不是一个)。大致上,我们问的对象是:你是否有意义?这是使用以下算法完成的:

  • 如果对象有一个__nonzero__特殊方法(与numeric built-ins、intfloat一样),则调用此方法。它必须返回直接使用的bool值,或者如果等于零,则返回被视为Falseint值。

  • 否则,如果对象有一个__len__特殊方法(如container built-ins、listdictsettuple…),则考虑到容器False为空(长度为零),它调用此方法。

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

  • 在第二个测试中,比较对象是否与None相等。在这里,我们问对象,"你是否等于另一个值?"这是使用以下算法完成的:

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

  • 否则,如果对象具有__cmp__方法,则调用它。此函数必须返回一个指示两个对象顺序的int(如果是self < other,则返回-1;如果是self == other,则返回0;如果是self > other,则返回+1

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

  • 使用is操作符可以进行另一个测试。我们会问这个物体,"你是这个特别的物体吗?"

    一般来说,我建议使用第一个具有非数值的测试,当您想比较具有相同性质的对象(两个字符串、两个数字等)时使用相等性测试,并且仅当使用sentinel值(例如,None表示没有为成员字段初始化,或者使用float时检查标识。1〕或__getitem__方法)。

    总而言之,我们有:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    >>> 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


    这实际上都是不好的做法。从前,人们认为随意地对待"无"和"假"是可以的。但是,由于python 2.2,这不是最好的策略。

    首先,当您执行if xif not x类型的测试时,python必须隐式地将x转换为boolean。bool函数的规则描述了一系列虚假的东西;其他的都是真的。如果x的值不是一个合适的布尔值,那么这种隐式转换并不是最清晰的表达方式。

    在python 2.2之前,没有bool函数,所以更不清楚。

    第二,你不应该真的用== None来测试。你应该使用is Noneis not None

    参见PEP8,python代码的样式指南。

    1
    2
    3
    4
    5
    6
    7
    - 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。因为你不太可能使用NotImplementedEllipsis,你也不会说if x is True(因为简单的if x更清楚),你只会测试None


    因为不是只有None被认为是错误的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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,因此您的两个代码段不相等。

    此外,考虑以下内容:

    1
    2
    3
    4
    >>> False == 0
    True
    >>> False == ()
    False

    if object:不是一种平等性检查。0()[]None{}等各不相同,但均为假。

    这就是短路表达式背后的"魔力",比如:

    1
    foo = bar and spam or eggs

    以下简称:

    1
    2
    3
    4
    if bar:
        foo = spam
    else:
        foo = eggs

    尽管你真的应该写:

    1
    foo = spam if bar else egg


    如果你问

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

    调用垃圾邮件的非零方法。从python手册:

    __nonzero__(self)
    Called to implement truth value testing, and the built-in operation bool(); should return False or True, or their integer equivalents 0 or 1. When this method is not defined, __len__() is called, if it is defined (see below). If a class defines neither __len__() nor __nonzero__(), all its instances are considered true.

    如果你问

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

    使用参数none调用垃圾邮件的 eq 方法。

    有关定制的更多信息,请访问https://docs.python.org/reference/datamodel.html basic customization查看python文档。


    PEP8——python代码的样式指南建议在测试none时使用is或is。

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

    另一方面,如果您测试的是非,那么应该使用布尔运算符。


    这两个比较有不同的目的。前者检查某物的布尔值,后者检查无值的标识。


    就我个人而言,我选择了跨语言的一致方法:只有当var声明为布尔值(或在C中定义为布尔值,我们没有特定类型)时,我才使用EDOCX1(或等效值)。我甚至在这些变量前面加上了一个b(所以实际上应该是bVar),以确保我不会在这里意外地使用另一个类型。我真的不喜欢隐式转换为布尔型,更不用说当有许多复杂的规则时。

    当然,人们会不同意。有些人走得更远,在我的Java代码中,我看到EDOCX1 50(太多余了!)其他人喜欢过多紧凑的语法,使用while (line = getNextLine()),对我来说太模糊了。


    答案是"视情况而定"。

    如果我认为0,",[]和false(list不是详尽的)在这个上下文中等同于none,那么使用第一个示例。


    首先,第一个例子更短,看起来更好。与其他文章一样,你选择什么也取决于你真正想用比较做什么。