我认为我完全理解这一点,但我只是想确保,因为我总是看到人说要 永远 对测试True,False或None。
True
False
None
他们建议例程应引发错误,而不是返回False或None。无论如何,在很多情况下,我只是想知道是否设置了标志,所以我的函数返回True或False。在其他情况下,如果没有有用的结果,我将有一个函数返回None。根据我的想法,只要我意识到我永远都不要使用:
if foo == True if foo == False if foo == None
而是应使用:
if foo is True if foo is False if foo is None
因为True,False和None都是单例,并且在使用“ is”而不是“ ==”时将始终评估我期望的方式。我在这里错了吗?
同样,修改有时返回None的函数,而不是引发错误,是否更Pythonic?
假设我有一个名为“ get_attr()”的实例方法,该方法从某些文件中检索属性。如果发现我请求的属性不存在,是否应该返回None?让他们提出错误并稍后发现它会更好吗?
该建议是不是说你不应该 使用 True,False或None。只是您不应该使用if x == True。
if x == True
if x == True很愚蠢,因为==它只是二进制运算符!它的返回值是True或False,具体取决于其参数是否相等。if condition如果condition正确,将继续进行。因此,当您编写if x == TruePython时,首先要进行评估x == True,True如果x为was True,False否则为true,如果结果为true,则继续执行。但是,如果您期望x是True或False,为什么不直接使用if x!
==
if condition
condition
x == True
x
if x
同样,x == False通常可以用代替not x。
x == False
not x
在某些情况下,您可能需要使用x == True。这是因为if语句条件是“在布尔上下文中求值”以查看其是否“真实”,而不是针对进行严格测试True。例如,if语句以及非零数字值都将非空字符串,列表和字典视为真,但都不等于True。因此,如果您想测试何时使用,则可以确定一个任意值是否 恰好是 该值True,而不仅是它是否真实if x == True。但是我几乎从来没有看到这种用法。非常罕见,如果您 确实 需要编写该注释,那么值得添加评论,以便将来的开发人员(包括您自己)不仅仅假设== True 是多余的,将其删除。
if
== True
使用x is True替代实际上更糟。你不应该使用is具有基本的内置不可变的类型,如布尔(True,False),数字和字符串。原因是对于这些类型,我们关心的是 价值 ,而不是 身份 。==测试这些类型的值是否相同,同时is始终测试身份。
x is True
is
测试身份而不是值是不好的,因为实现理论上可以构造新的布尔值而不是查找现有的值,从而导致您拥有两个True具有相同值的值,但是它们存储在内存中的不同位置并且具有不同的身份。实际上,我非常确定,True并且FalsePython解释器总是会重用它,因此不会发生这种情况,但这实际上是实现细节。这个问题使人们无时无刻不在使用字符串,因为直接出现在程序源中的短字符串和文字字符串被Python回收,因此'foo' is 'foo'始终会返回True。但是很容易以两种不同的方式构造相同的字符串,并让Python为它们提供不同的身份。请注意以下几点:
'foo' is 'foo'
>>> 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
正如在Python 2.3.5中引入布尔时的注释中所解释的那样,其基本原理是使用整数1和0表示True和False的旧行为是好的,但是我们只想为我们想要的数字提供更多描述性的名称代表真相值。
实现该目标的一种方法是简单地内置True = 1并False = 0内置。那么1和True确实是无法区分的(包括by is)。但这也意味着返回的函数True将显示1在交互式解释器中,因此要做的是将其创建bool为的子类型int。唯一不同的bool是strand repr; bool实例仍然具有与int实例相同的数据,并且仍以相同的方式比较相等性,因此True == 1。
True = 1
False = 0
1
bool
int
str
repr
True == 1
因此,x is True当x某些代码可能期望“ True只是拼写1的另一种方式”设置了代码时,使用这种方法是错误的,因为有很多方法可以构造与它相等True但不相同的值:
>>> 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 == True当whenx可以是任意Python值并且只想知道它是否为Boolean值时,使用错误True。我们唯一可以确定的是,x当您只想测试“真实性”时,仅使用最佳方法。值得庆幸的是,通常至少在我编写的代码中这就是全部!
更确定的方法是x == True and type(x) is bool。但是对于一个晦涩难懂的案例来说,这变得非常冗长。通过执行显式类型检查,它看起来也不是Python风格的……但这确实是您在尝试精确测试True而不是真实测试时所要做的。鸭子的输入方式是接受真实值,并允许任何用户定义的类将自己声明为真实。
x == True and type(x) is bool
如果您要处理非常精确的真理概念,那么您不仅不认为非空集合为真,而且不认为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。
if x is None
if not x
我关于使用==而不是is不可变值类型的论点建议您应该使用if x == None而不是if x is None。但是,就NonePython而言,它确实明确保证None了整个宇宙中只有一个,并且常规惯用的Python代码使用is。
if x == None
关于返回None还是引发异常,取决于上下文。
对于您的get_attr示例,我希望它会引发异常,因为我将称呼为like do_something_with(get_attr(file))。调用者的通常期望是,他们将获得属性值,并且让他们获得None并假定该属性值是一个危险的危险,而不是忘记处理异常(如果您无法继续该属性而实际上可以继续),那么危险就更大了。找到了。另外,返回None指示失败意味着None该属性无效。在某些情况下这可能是个问题。
get_attr
do_something_with(get_attr(file))
对于像的虚函数see_if_matching_file_exists,我们提供了一个模式,并检查几个位置以查看是否存在匹配项,如果找到一个匹配项,或者找不到匹配项,则可能返回匹配项None。但是,它也可以返回匹配列表。那么没有匹配项就是空列表(它也是“ falsey”;这是我只是if x用来查看是否收到任何东西的情况之一)。
see_if_matching_file_exists
因此,当在异常之间进行选择并None指示失败时,必须确定是否None为期望的非失败值,然后查看调用该函数的代码的期望。如果“正常”的期望是将返回一个有效值,并且无论是否返回一个有效值,调用者仅偶尔能够正常工作,那么您应该使用异常来指示失败。如果没有有效值是很常见的,那么调用者将期望同时处理这两种可能性,那么您可以使用None。