建议并不是说您永远不要使用True、False 或None。只是你不应该使用if x == True。
if x == True 很傻,因为== 只是一个二元运算符!它的返回值为True 或False,具体取决于其参数是否相等。如果condition 为真,if condition 将继续。因此,当您编写if x == True 时,Python 将首先评估x == True,如果x 为True 和False,则它将变为True,否则,如果结果为真则继续。但是,如果您希望 x 是 True 或 False,为什么不直接使用 if x!
同样,x == False 通常可以替换为 not x。
在某些情况下,您可能需要使用x == True。这是因为if 语句条件是“在布尔上下文中评估”以查看它是否“真实”,而不是完全针对True 进行测试。例如,非空字符串、列表和字典都被 if 语句视为真值,以及非零数值,但它们都不等于 True。因此,如果您想测试任意值是否完全 值True,而不仅仅是它是否真实,何时使用if x == True。但我几乎从来没有看到它的用途。这种情况非常罕见,如果您确实需要写它,那么值得添加评论,这样未来的开发人员(可能包括您自己)就不会仅仅认为== True 是多余的并将其删除。 p>
使用x is True 实际上更糟。永远不要将is 与基本的内置不可变类型一起使用,例如布尔值(True、False)、数字和字符串。原因是对于这些类型,我们关心的是值,而不是身份。 == 测试这些类型的值是否相同,而is 始终测试身份。
测试身份而不是值是不好的,因为从理论上讲,实现可以构造新的布尔值而不是查找现有的布尔值,导致您拥有两个具有相同值的 True 值,但它们存储在内存中的不同位置并且有不同的身份。在实践中,我很确定 True 和 False 总是被 Python 解释器重用,所以这不会发生,但这确实是一个实现细节。这个问题总是让人们对字符串感到困惑,因为直接出现在程序源中的短字符串和文字字符串被 Python 回收,所以'foo' is 'foo' 总是返回True。但是很容易以两种不同的方式构造相同的字符串,并让 Python 赋予它们不同的身份。请注意以下几点:
>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True
编辑:所以事实证明 Python 在布尔值上的相等性有点出乎意料(至少对我来说):
>>> True is 1
False
>>> True == 1
True
>>> True == 2
False
>>> False is 0
False
>>> False == 0
True
>>> False == 0.0
True
正如the notes when bools were introduced in Python 2.3.5 中所解释的,这样做的基本原理是使用整数 1 和 0 来表示 True 和 False 的旧行为是好的,但我们只是想要更多描述性的名称来表示我们打算表示真值的数字。
实现这一目标的一种方法是在内置函数中简单地使用True = 1 和False = 0;那么 1 和 True 真的无法区分(包括is)。但这也意味着返回True 的函数将在交互式解释器中显示1,因此所做的是创建bool 作为int 的子类型。 bool 唯一不同的是str 和repr; bool 实例仍然具有与 int 实例相同的数据,并且仍然以相同的方式比较相等性,因此 True == 1。
因此,当 x 可能由一些期望“True 只是拼写 1 的另一种方式”的代码设置时使用 x is True 是错误的,因为有很多方法可以构造等于 @ 的值987654380@但与它的身份不同:
>>> a = 1L
>>> b = 1L
>>> c = 1
>>> d = 1.0
>>> a == True, b == True, c == True, d == True
(True, True, True, True)
>>> a is b, a is c, a is d, c is d
(False, False, False, False)
当x 可以是任意Python 值并且您只想知道它是否是布尔值True 时,使用x == True 是错误的。我们唯一可以确定的是,当您只想测试“真实性”时,最好只使用x。值得庆幸的是,这通常是所需要的,至少在我编写的代码中是这样!
更可靠的方法是x == True and type(x) is bool。但是对于一个非常晦涩的案例来说,这变得非常冗长。通过进行显式类型检查,它看起来也不是很 Pythonic……但这确实是您尝试精确测试 True 而不是真话时所做的;鸭子类型的方式是接受真值并允许任何用户定义的类声明自己是真值。
如果您正在处理这种极其精确的真理概念,您不仅不认为非空集合为真,而且也不认为 1 为真,那么只使用 x is True 可能没问题, 因为大概你知道x 不是来自认为 1 为真的代码。我认为没有任何纯 python 方法可以提出另一个位于不同内存地址的True(尽管您可能可以从 C 中做到这一点),因此尽管理论上是“错误的”,但它永远不会中断" 要做的事情。
我以前认为布尔值很简单!
结束编辑
但是,对于None,习惯用法是使用if x is None。在许多情况下,您可以使用if not x,因为None 是if 语句的“错误”值。但最好仅在您想以相同方式处理所有虚假值(零值数字类型、空集合和None)时才这样做。如果您正在处理的值要么是某个可能的其他值,要么是 None 以指示“无值”(例如当函数在失败时返回 None),那么要好得多使用if x is None,这样您就不会在函数恰好返回一个空列表或数字 0 时意外假设该函数失败。
对于不可变值类型使用== 而不是is 的论点建议您应该使用if x == None 而不是if x is None。但是,在None 的情况下,Python 确实明确保证整个宇宙中只有一个None,并且正常的惯用Python 代码使用is。
返回None还是抛出异常,取决于上下文。
对于像您的 get_attr 示例,我希望它会引发异常,因为我将像 do_something_with(get_attr(file)) 一样调用它。调用者的正常期望是他们将获得属性值,并让他们获得 None 并假设这是属性值比忘记处理异常要严重得多,因为如果属性可以继续,您实际上可以继续找不到。另外,返回None 表示失败意味着None 不是该属性的有效值。在某些情况下,这可能是个问题。
对于像see_if_matching_file_exists 这样的虚构函数,我们提供了一个模式,它会检查多个位置以查看是否存在匹配项,如果找到匹配项,则返回匹配项,否则返回None。但或者它可以返回一个匹配列表;那么没有匹配的只是空列表(这也是“错误的”;这是我只需使用if x 来查看是否有任何返回的情况之一)。
所以当在异常和None 表示失败之间进行选择时,您必须确定None 是否是预期的非失败值,然后查看调用该函数的代码的预期。如果“正常”期望是返回一个有效值,并且无论是否返回有效值,调用者只是偶尔能够正常工作,那么您应该使用异常来指示失败。如果没有有效值是很常见的,那么调用者会期望处理这两种可能性,那么您可以使用None。