在Python函数中使用True,False和None作为返回值
我认为我完全理解这一点,但我只是想确保自从我一直看到人们说永远不会对True
, False
,或None
。 他们build议例程应该提出一个错误,而不是返回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? 让他们提出一个错误并在以后抓到它会更好吗?
build议不是说你不应该使用 True
, False
或None
。 只是if x == True
,你不应该使用。
if x == True
是愚蠢的,因为==
只是一个二元运算符! 它的返回值是True
或False
,取决于它的参数是否相等。 if condition
将会继续。 所以当你写的时候, if x == True
Python将首先计算x == True
,如果x
为True
,则返回True
,否则返回False
,如果结果为true,则继续。 但是如果你希望x
是True
或False
,那么为什么不直接使用if x
?
同样, x == False
通常可以被replace为not x
。
在某些情况下,您可能需要使用x == True
。 这是因为if
语句的条件是“在布尔上下文中求值”来查看它是否是“truthy”,而不是完全testingTrue
。 例如,非空string,列表和字典都被if语句和非零数字值视为True
,但是都不等于True
。 所以如果你想testing一个任意的值是否正好是True
的值,不仅仅是真的,如果你使用if x == True
。 但是我几乎从来没有看到这样的用途。 这是非常罕见的,如果你真的需要写这个,值得添加一个评论,所以未来的开发人员(包括可能你自己)不只是假设== True
是多余的,并将其删除。
使用x is True
而实际上更糟。 你不应该使用基本的内置不变types,如布尔值( True
, False
),数字和string。 原因是,对于这些types,我们关心价值观 ,而不是认同 。 ==
testing这些types的值是相同的,而总是testing身份。
testing身份而不是价值是不好的,因为一个实现可以在理论上构造新的布尔值,而不是去找现有的值,导致你有两个具有相同的值,但存储在不同的内存中,具有不同的身份True
值。 在实践中,我相当肯定True
和False
总是被Python解释器重复使用,所以这不会发生,但这实际上是一个实现细节。 这个问题总是以stringforms出现,因为直接出现在程序源代码中的短string和string被Python回收,所以'foo' is 'foo'
总是返回True
。 但是用两种不同的方式构造相同的string很容易,并且让Python给它们不同的标识。 注意以下几点:
>>> stars1 = ''.join('*' for _ in xrange(100)) >>> stars2 = '*' * 100 >>> stars1 is stars2 False >>> stars1 == stars2 True
编辑:所以事实certificate,Python的平等布尔是有点意外的(至less对我来说):
>>> 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中引入bools时的注释中所解释的,基本原理是使用整数1和0来表示True和False的旧行为是好的,但是我们只是想为我们打算的数字使用更多的描述性名称代表真理价值。
实现这一目标的一种方法是在内build中只需要True = 1
和False = 0
; 那么1和真实将是无法区分的(包括is
)。 但是这也意味着一个返回True
的函数会在交互式解释器中显示1
,所以相反,将bool
创build为int
的子types。 关于bool
唯一不同的是str
和repr
; bool
实例仍然与int
实例具有相同的数据,并且仍然以相同的方式比较相等性,所以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
可以是一个任意的Python值,并且只想知道它是否为布尔值True
时,使用x == True
是错误的。 我们唯一可以肯定的是,当你只是想testing“真实性”时,最好使用x
。 谢天谢地,这通常是所有必需的,至less在我写的代码中!
更确定的方式是x == True and type(x) is bool
。 但是,对于一个非常模糊的情况,这已经变得非常冗长了。 通过进行明确的types检查,它也不会显得非常焦躁……但是当你试图精确地testingTrue
而不是Truthy时,这就是你正在做的事情; 鸭子的打字方式是接受真理值,并允许任何用户定义的类声明自己是真理。
如果你正在处理这个非常精确的真理概念,你不仅不认为非空集合是真的,而且也不认为1是真的,那么只用x is True
可能是可以的,因为可以假设那么你知道x
不是来自认为1是真的代码。 我不认为有任何纯python的方式来提出另一个True
生活在不同的内存地址(虽然你可以从C做),所以这应该永远不会打破,尽pipe在理论上是“错误”的事情去做。
我以前认为布尔人很简单!
结束编辑
然而,在None
的情况下, if x is None
,则使用该习语。 在很多情况下, if not x
,你可以使用,因为None
对于if
语句是一个“假”的值。 但是如果你想以同样的方式处理所有错误的值(零值数字types,空集合和None
),最好只做这个。 如果你正在处理一个可能是其他值的值,或者用None
来表示“没有值”(例如当一个函数在失败时返回None
),那么if x is None
,那么它会好得多,所以你不需要意外地假设函数失败时,它只是返回一个空的列表,或数字0。
我使用==
而不是用于不可变的值types的参数将build议您应该使用if x == None
而不是if x is None
。 但是,对于None
Python确实明确保证在整个Universe中只有一个None
,而普通的惯用Python代码使用的is
。
关于是否返回None
或引发exception,取决于上下文。
对于像你的get_attr
例子的东西,我期望它会引发一个exception,因为我打算把它叫做do_something_with(get_attr(file))
。 调用者的正常期望是他们将得到属性值,并让他们得到None
并且假设属性值比忘记处理exception的危险要严重得多,如果属性不能实际上可以继续被发现。 另外,返回None
来指示失败意味着None
不是该属性的有效值。 在某些情况下,这可能是一个问题。
对于像see_if_matching_file_exists
这样的假想函数,我们提供了一个模式,并检查了几个地方,看看是否有匹配,如果find了匹配,它可以返回一个匹配,否则返回一个匹配。 但是也可以返回一个匹配列表。 那么没有匹配就只是空的列表(这也是“假的”;这是其中的一个情况,我只是使用if x
来看看我有什么东西回来)。
所以当在exception和None
之间select来指示失败时,你必须决定None
是否是一个预期的非失败值,然后看看调用该函数的代码的期望值。 如果“正常”期望是返回一个有效值,并且只有偶尔调用者能够正常工作,而不pipe返回的是否有效值,那么您应该使用exception来指示失败。 如果没有任何有效值的情况会非常普遍,那么呼叫者将期望处理这两种可能性,那么您可以使用None
。
if foo
使用if foo
或者if not foo
,则不需要使用==
或者为此。
对于检查无,检查is None
, is not None
build议。 这允许您将它与False区分开(或者评估为False的事物,如""
和“ []
)。
get_attr
是否应该返回None
取决于上下文。 你可能有一个值为None的属性,你不能这样做。 我将“ None
”解释为“未设置”,而KeyError
表示该文件中不存在该键。
如果检查真相:
if foo
对于错误:
if not foo
没有:
if foo is None
对于非无:
if foo is not None
对于getattr()
,正确的行为不是返回None
而是引发AttributError
错误 – 除非你的类是类似于defaultdict
关于是否提出exception或返回None
:这取决于用例。 要么是pythonic。 例如,看python的dict
类, x[y]
钩入dict.__getitem__
,如果key不存在,则会引发dict.__getitem__
。 但是如果key不存在, dict.get
方法返回第二个参数(默认为None
)。 他们都是有用的。
要考虑的最重要的事情是在文档string中logging该行为,并确保您的get_attr()
方法执行它所做的事情。
要解决您的其他问题,请使用以下约定:
if foo: # for testing truthiness if not foo: # for testing falsiness if foo is None: # testing .. Noneliness ? if foo is not None: # check explicitly avoids common bugs caused by empty sequences being false
返回True
或False
函数可能应该有一个名称,这可以显着提高代码的可读性
def is_running_on_windows(): return os.name == 'nt'
在python3中,你可以“键入提示”:
>>> def is_running_on_windows() -> bool: ... return os.name == 'nt' ... >>> is_running_on_windows.__annotations__ {'return': bool}
你可以直接检查那个variables是否包含值,或者不是像if var
或者not var
。
在PEP 8(Python代码样式指南)文档的例子中,我看到foo is None
或者foo is not None
,而不是foo == None
或者foo != None
。 if boolean_value
在本文档中推荐使用,而不是if boolean_value == True
或者if boolean_value is True
。 所以我认为如果这是Python的官方方式,我们Python的人也应该这样。
问候。
在虚构的getattr
函数的情况下,如果请求的属性总是可用的,但不是那么抛出一个错误。 如果该属性是可选的,则返回None
。
为真,不是无:
if foo:
对于假,无:
if not foo:
有一件事是确保没有任何东西可以重新分配你的variables。 如果最终不是布尔型,依靠真实性会导致错误。 dynamictypes语言的条件编程之美:)。
以下打印“ 否 ”。
x = False if x: print 'yes' else: print 'no'
现在让我们改变x 。
x = 'False'
现在声明打印“ 是 ”,因为string是真的。
if x: print 'yes' else: print 'no'
但是,该陈述正确地输出“ 否 ”。
if x == True: print 'yes' else: print 'no'