在 Python 函数中使用 True、False 和 None 作为返回值 [英] Use of True, False, and None as return values in Python functions

查看:54
本文介绍了在 Python 函数中使用 True、False 和 None 作为返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为我完全理解这一点,但我只是想确定一下,因为我一直看到人们说永远针对 True 进行测试,FalseNone.

他们建议例程应该引发错误而不是返回 False 或 None.无论如何,我在很多情况下只想知道是否设置了标志,因此我的函数返回 True 或 False.还有其他情况,如果没有有用的结果,我有一个函数返回 None .从我的想法来看,只要我意识到我永远不应该使用:

if foo == True如果 foo == False如果 foo == 无

而应该使用:

如果 foo 为 True如果 foo 是 False如果 foo 是 None

因为 True、False 和 None 都是单例,并且在使用is"而不是=="时总是会以我期望的方式进行评估.我错了吗?

与此类似,修改有时返回 None 的函数以便它们引发错误会更 Pythonic 吗?

假设我有一个名为get_attr()"的实例方法,它从某个文件中检索一个属性.在发现我请求的属性不存在的情况下,返回None是否合适?让他们提出错误并在以后捕获它会更好吗?

解决方案

建议不是永远不要使用 True, False.只是你不应该使用if x == True.

if x == True 很傻,因为 == 只是一个二元运算符!它有一个 TrueFalse 的返回值,这取决于它的参数是否相等.如果 condition 为真,if condition 将继续.因此,当您编写 if x == True 时,Python 将首先评估 x == True,如果 x,它将变为 TrueTrueFalse 否则,如果结果为真,则继续.但是,如果您希望 xTrueFalse,为什么不直接使用 if x

同样,x == False 通常可以替换为 not x.

在某些情况下,您可能需要使用 x == True.这是因为 if 语句条件是在布尔上下文中评估"以查看它是否真实",而不是针对 True 进行精确测试.例如,非空字符串、列表和字典都被 if 语句视为真值,以及非零数值,但它们都不等于 True.因此,如果您想测试任意值是否恰好是值 True,而不仅仅是它是否为真值,那么当您使用 if x == True.但我几乎从未看到它的用途.这种情况非常罕见,如果您确实需要编写它,那么值得添加注释,以便未来的开发人员(可能包括您自己)不要只是假设 == True 是多余并删除它.

<小时>

使用 x is True 实际上更糟.永远不要将 is 与基本的内置不可变类型一起使用,例如布尔值 (True, False)、数字和字符串.原因是对于这些类型,我们关心,而不是身份.== 测试这些类型的值是否相同,而 is 始终测试身份.

测试身份而不是值是不好的,因为一个实现理论上可以构造新的布尔值而不是去查找现有的值,导致您有两个具有相同值的 True 值,但它们被存储在记忆中的不同地方,有不同的身份.在实践中,我很确定 TrueFalse 总是被 Python 解释器重用,所以这不会发生,但这确实是一个实现细节.这个问题总是让人们被字符串绊倒,因为直接出现在程序源代码中的短字符串和文字字符串会被 Python 回收,所以 'foo' is 'foo' 总是返回 True.但是很容易以两种不同的方式构造相同的字符串并让 Python 赋予它们不同的身份.请注意以下事项:

<预><代码>>>>stars1 = ''.join('*' for _ in xrange(100))>>>星星 2 = '*' * 100>>>星星 1 是星星 2错误的>>>星星 1 == 星星 2真的

所以事实证明 Python 在布尔值上的相等性有点出乎意料(至少对我而言):

<预><代码>>>>真的是 1错误的>>>真 == 1真的>>>真 == 2错误的>>>错误为 0错误的>>>错误 == 0真的>>>错误 == 0.0真的

这样做的基本原理,如注释中所述布尔值是在 Python 2.3.5 中引入的,这是使用整数 1 和 0 来表示 True 和 False 的旧行为是好的,但我们只是想要更多描述性的名称来表示我们打算表示真值的数字.>

实现这一目标的一种方法是在内置函数中简单地使用 True = 1False = 0;那么 1 和 True 真的是无法区分的(包括 is).但这也意味着返回 True 的函数会在交互式解释器中显示 1,所以我们所做的是创建 bool 作为子类型int.bool 唯一不同的是 strreprbool 实例仍然与 int 实例具有相同的数据,并且仍然以相同的方式比较相等性,因此 True == 1.

所以当 x 可能由一些期望True 只是拼写 1 的另一种方式"的代码设置时,使用 x is True 是错误的,因为有有很多方法可以构造等于 True 但不具有相同标识的值:

<预><代码>>>>一 = 1L>>>b = 1L>>>c = 1>>>d = 1.0>>>a == 真,b == 真,c == 真,d == 真(真、真、真、真)>>>a是b,a是c,a是d,c是d(假,假,假,假)

x 可能是任意 Python 值而您只想知道它是否是布尔值 True 时,使用 x == True 是错误的.我们唯一可以确定的是,当您只想测试真实性"时,仅使用 x 是最好的.值得庆幸的是,这通常就是所需要的,至少在我编写的代码中是如此!

更可靠的方法是 x == True and type(x) is bool.但是对于一个非常晦涩的案例,这变得非常冗长.通过进行显式类型检查,它看起来也不是很 Pythonic……但这确实是您尝试精确测试 True 而不是truthy 时所做的;鸭子输入方式是接受真值并允许任何用户定义的类声明自己为真.

如果您正在处理这种极其精确的真理概念,您不仅不认为非空集合为真,而且也不认为 1 为真,那么只需使用 x is True 可能没问题,因为大概你知道 x 不是来自认为 1 为真的代码.我不认为有任何纯 python 方法可以想出另一个位于不同内存地址的 True(尽管您可能可以从 C 中做到这一点),所以尽管如此,这应该永远不会中断理论上是错误"的事情.

我曾经认为布尔值很简单!

结束编辑

<小时>

None的情况下,习惯用法是使用if x is None.在许多情况下,您可以使用 if not x,因为 Noneif 语句的假"值.但最好仅在您希望以相同方式处理所有假值(零值数字类型、空集合和 None)时才这样做.如果您正在处理的值是其他可能的值或 None 以指示无值"(例如当函数在失败时返回 None 时),那么它是使用 if x is None 更好,这样您就不会意外地假设函数在刚好返回一个空列表或数字 0 时失败了.

我对于不可变值类型使用 == 而不是 is 的论点建议您应该使用 if x == None 而不是如果 x 是 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.

I think that I fully understand this, but I just want to make sure since I keep seeing people say to never ever test against True, False, or None.

They suggest that routines should raise an error rather than return False or None. Anyway, I have many situations where I simply want to know if a flag is set or not so my function returns True or False. There are other situations where I have a function return None if there was no useful result. From my thinking, neither is problematic so long as I realize that I should never use:

if foo == True
if foo == False
if foo == None

and should instead use:

if foo is True
if foo is False
if foo is None

since True, False, and None are all singletons and will always evaluate the way I expect when using "is" rather than "==". Am I wrong here?

Along the same lines, would it be more Pythonic to modify the functions that sometimes return None so that they raise an error instead?

Say I have an instance method called "get_attr()" that retrieves an attribute from some file. In the case where it finds that the attribute I requested does not exist, is it appropriate to return None? Would it be better to have them raise an error and catch it later?

解决方案

The advice isn't that you should never use True, False, or None. It's just that you shouldn't use if x == True.

if x == True is silly because == is just a binary operator! It has a return value of either True or False, depending on whether its arguments are equal or not. And if condition will proceed if condition is true. So when you write if x == True Python is going to first evaluate x == True, which will become True if x was True and False otherwise, and then proceed if the result of that is true. But if you're expecting x to be either True or False, why not just use if x directly!

Likewise, x == False can usually be replaced by not x.

There are some circumstances where you might want to use x == True. This is because an if statement condition is "evaluated in Boolean context" to see if it is "truthy" rather than testing exactly against True. For example, non-empty strings, lists, and dictionaries are all considered truthy by an if statement, as well as non-zero numeric values, but none of those are equal to True. So if you want to test whether an arbitrary value is exactly the value True, not just whether it is truthy, when you would use if x == True. But I almost never see a use for that. It's so rare that if you do ever need to write that, it's worth adding a comment so future developers (including possibly yourself) don't just assume the == True is superfluous and remove it.


Using x is True instead is actually worse. You should never use is with basic built-in immutable types like Booleans (True, False), numbers, and strings. The reason is that for these types we care about values, not identity. == tests that values are the same for these types, while is always tests identities.

Testing identities rather than values is bad because an implementation could theoretically construct new Boolean values rather than go find existing ones, leading to you having two True values that have the same value, but they are stored in different places in memory and have different identities. In practice I'm pretty sure True and False are always reused by the Python interpreter so this won't happen, but that's really an implementation detail. This issue trips people up all the time with strings, because short strings and literal strings that appear directly in the program source are recycled by Python so 'foo' is 'foo' always returns True. But it's easy to construct the same string 2 different ways and have Python give them different identities. Observe the following:

>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True

EDIT: So it turns out that Python's equality on Booleans is a little unexpected (at least to me):

>>> True is 1
False
>>> True == 1
True
>>> True == 2
False
>>> False is 0
False
>>> False == 0
True
>>> False == 0.0
True

The rationale for this, as explained in the notes when bools were introduced in Python 2.3.5, is that the old behaviour of using integers 1 and 0 to represent True and False was good, but we just wanted more descriptive names for numbers we intended to represent truth values.

One way to achieve that would have been to simply have True = 1 and False = 0 in the builtins; then 1 and True really would be indistinguishable (including by is). But that would also mean a function returning True would show 1 in the interactive interpreter, so what's been done instead is to create bool as a subtype of int. The only thing that's different about bool is str and repr; bool instances still have the same data as int instances, and still compare equality the same way, so True == 1.

So it's wrong to use x is True when x might have been set by some code that expects that "True is just another way to spell 1", because there are lots of ways to construct values that are equal to True but do not have the same identity as it:

>>> 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)

And it's wrong to use x == True when x could be an arbitrary Python value and you only want to know whether it is the Boolean value True. The only certainty we have is that just using x is best when you just want to test "truthiness". Thankfully that is usually all that is required, at least in the code I write!

A more sure way would be x == True and type(x) is bool. But that's getting pretty verbose for a pretty obscure case. It also doesn't look very Pythonic by doing explicit type checking... but that really is what you're doing when you're trying to test precisely True rather than truthy; the duck typing way would be to accept truthy values and allow any user-defined class to declare itself to be truthy.

If you're dealing with this extremely precise notion of truth where you not only don't consider non-empty collections to be true but also don't consider 1 to be true, then just using x is True is probably okay, because presumably then you know that x didn't come from code that considers 1 to be true. I don't think there's any pure-python way to come up with another True that lives at a different memory address (although you could probably do it from C), so this shouldn't ever break despite being theoretically the "wrong" thing to do.

And I used to think Booleans were simple!

End Edit


In the case of None, however, the idiom is to use if x is None. In many circumstances you can use if not x, because None is a "falsey" value to an if statement. But it's best to only do this if you're wanting to treat all falsey values (zero-valued numeric types, empty collections, and None) the same way. If you are dealing with a value that is either some possible other value or None to indicate "no value" (such as when a function returns None on failure), then it's much better to use if x is None so that you don't accidentally assume the function failed when it just happened to return an empty list, or the number 0.

My arguments for using == rather than is for immutable value types would suggest that you should use if x == None rather than if x is None. However, in the case of None Python does explicitly guarantee that there is exactly one None in the entire universe, and normal idiomatic Python code uses is.


Regarding whether to return None or raise an exception, it depends on the context.

For something like your get_attr example I would expect it to raise an exception, because I'm going to be calling it like do_something_with(get_attr(file)). The normal expectation of the callers is that they'll get the attribute value, and having them get None and assume that was the attribute value is a much worse danger than forgetting to handle the exception when you can actually continue if the attribute can't be found. Plus, returning None to indicate failure means that None is not a valid value for the attribute. This can be a problem in some cases.

For an imaginary function like see_if_matching_file_exists, that we provide a pattern to and it checks several places to see if there's a match, it could return a match if it finds one or None if it doesn't. But alternatively it could return a list of matches; then no match is just the empty list (which is also "falsey"; this is one of those situations where I'd just use if x to see if I got anything back).

So when choosing between exceptions and None to indicate failure, you have to decide whether None is an expected non-failure value, and then look at the expectations of code calling the function. If the "normal" expectation is that there will be a valid value returned, and only occasionally will a caller be able to work fine whether or not a valid value is returned, then you should use exceptions to indicate failure. If it will be quite common for there to be no valid value, so callers will be expecting to handle both possibilities, then you can use None.

这篇关于在 Python 函数中使用 True、False 和 None 作为返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆