在python函数中使用True,False和None作为返回值

时间:2012-02-29 06:16:30

标签: python

我认为我完全理解这一点,但我只是想确保,因为我一直看到有人说永远不会对TrueFalseNone进行测试。他们建议例程应该引发错误而不是返回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是否合适?让他们提出错误并在以后发现它会更好吗?

9 个答案:

答案 0 :(得分:62)

建议不要使用 TrueFalseNone。只是你不应该使用if x == True

if x == True很愚蠢,因为==只是一个二元运算符!它的返回值为TrueFalse,具体取决于其参数是否相等。如果if condition为真,condition将继续进行。因此,当您编写if x == True时,Python将首先评估x == True,如果Truex则为True,否则为False,然后如果结果为真则继续。但是,如果您希望x成为TrueFalse,为什么不直接使用if x

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

在某些情况下,您可能希望使用x == True。这是因为if语句条件是在布尔上下文"中评估的。看看它是不是" truthy"而不是完全针对True进行测试。例如,非空字符串,列表和字典都被if语句认为是真实的,以及非零数字值,但这些都不等于True。因此,如果您想测试任意值是否完全True,而不仅仅是它是否真实,何时使用if x == True。但我几乎从来没有看到过这方面的用途。它非常罕见,如果你需要写它,那么值得添加评论,以便未来的开发人员(包括可能你自己)不要假设{ {1}}是多余的并将其删除。


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

测试身份而不是值是错误的,因为理论上实现可以构造新的布尔值而不是找到现有的布尔值,导致您有两个is值具有相同的值但存储在不同的内存中并有不同的身份。在实践中,我非常确定TrueTrue总是被Python解释器重复使用,所以这不会发生,但这确实是一个实现细节。这个问题一直伴随着字符串,因为直接出现在程序源中的短字符串和文字字符串被Python回收,因此False总是返回'foo' is 'foo'。但是以两种不同的方式构造相同的字符串很容易,Python让它们具有不同的身份。请注意以下事项:

True

编辑:事实证明,Python在布尔值上的平等有点出乎意料(至少在我看来):

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

正如the notes when bools were introduced in Python 2.3.5中所解释的那样,基本原理是使用整数1和0来表示True和False的旧行为是好的,但我们只是想要更多描述性的名称来表示我们想要代表真理的数字值。

实现这一目标的一种方法是在内置函数中简单地使用>>> True is 1 False >>> True == 1 True >>> True == 2 False >>> False is 0 False >>> False == 0 True >>> False == 0.0 True True = 1;然后1和True真的无法区分(包括False = 0)。但这也意味着返回is的函数会在交互式解释器中显示True,所以完成的是创建1作为{{1}的子类型}。关于bool的唯一不同之处是intbool; str个实例仍然与repr个实例具有相同的数据,并且仍以相同的方式比较相等,因此bool

因为int可能是由某些代码设置的True == 1使用x is True所以错误,因为#34; True只是拼写1"的另一种方式,因为有很多方法可以构造等于x但不具有相同身份的值:

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) 可能是任意Python值并且您只想知道它是否是布尔值x == True时,使用x是错误的。我们唯一确定的是,当你只想测试"真实性时,只使用True是最好的。值得庆幸的是,通常只需要这一切,至少在我写的代码中!

更确定的方式是x。但是,对于一个相当模糊的案例,它变得非常冗长。通过进行明确的类型检查,它看起来也不像Pythonic ......但是当你试图精确地测试x == True and type(x) is bool而不是真正的时候,这就是你正在做的事情。 duck typing方式是接受truthy值并允许任何用户定义的类声明自己是真实的。

如果你正在处理这个非常精确的真理概念,你不仅不认为非空集合是真实的,而且也不要认为1是真的,那么只需使用True可能没问题,因为大概你知道x is True并非来自认为1为真的代码。我不认为有任何纯粹的蟒蛇方式来提出另一个x生活在不同的内存地址(尽管你可以从C中做到),所以这不应该&#39尽管从理论上来说是错误的,但是它还是会被打破。要做的事。

我以前认为布尔很简单!

结束修改


但是,在True的情况下,成语是使用None。在许多情况下,您可以使用if x is None,因为if not x是" falsey"值为None语句。但是,如果您想要以同样的方式处理所有虚假值(零值数字类型,空集合和if),那么最好只执行此操作。如果您正在处理的值是某个可能的其他值,或None表示"没有值" (例如当一个函数在失败时返回None),然后它 更好地使用None,这样你就不会意外地承担这个功能它只是碰巧返回一个空列表或数字0时失败。

我使用if x is None而不是==来表示不可变值类型的论点建议您使用is而不是if x == None。但是,在if x is None的情况下,Python明确保证整个Universe中只有一个None,而正常的惯用Python代码使用None


关于是否返回is或引发异常,它取决于上下文。

对于类似None示例的内容,我希望它会引发异常,因为我会像get_attr一样调用它。调用者的正常期望是他们获取属性值,并让他们得到do_something_with(get_attr(file))并假设属性值比忘记处理异常时更危险如果找不到该属性。另外,返回None表示失败意味着None不是属性的有效值。在某些情况下,这可能是个问题。

对于像None这样的假想函数,我们提供了一个模式,它会检查多个地方以查看是否匹配,如果找到一个或see_if_matching_file_exists,它可以返回匹配如果它没有。但另外它可以返回一个匹配列表;然后,没有匹配只是空列表(这也是"假的&#34 ;;这是我只是使用None来查看我是否有任何回报的情况之一。 / p>

因此,当在异常和if x之间进行选择以指示失败时,您必须确定None是否是预期的非失败值,然后查看调用该函数的代码的期望。如果"正常"期望是会返回一个有效值,并且只有在调用者能够正常工作(无论是否返回有效值)时,您应该使用异常来指示失败。如果没有有效值是很常见的,那么调用者将期望处理这两种可能性,然后你可以使用None

答案 1 :(得分:13)

使用if fooif not foo,无需==is

要检查无,建议使用is Noneis not None。这允许您将其与False(或评估为False的内容区分开来,例如""[])。

get_attr是否应返回None取决于上下文。您可能有一个值为None的属性,您将无法执行此操作。我会将None解释为“未设置”,而KeyError则表示该文件中不存在该密钥。

答案 2 :(得分:7)

如果检查真相:

if foo

表示错误:

if not foo

表示无:

if foo is None

表示非人:

if foo is not None

对于getattr(),正确的行为会返回None但会引发AttributError错误 - 除非您的类类似于defaultdict

答案 3 :(得分:6)

关于是否提出异常或返回None:这取决于用例。两者都可以是pythonic。例如,查看python的dict类,x[y]挂钩到dict.__getitem__,如果不存在,则会引发KeyError。但是如果key不存在,dict.get方法返回第二个参数(默认为None)。 它们都很有用。

要考虑的最重要的事情是在docstring中记录该行为,并确保您的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

返回TrueFalse的函数应该有一个名称,可以明显改善代码的可读性

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}

答案 4 :(得分:1)

您可以直接检查该变量是否包含值if varnot var

答案 5 :(得分:1)

PEP 8(Style Guide for Python Code) document的示例中,我看到正在使用foo is Nonefoo is not None而不是foo == Nonefoo != None。此文档中建议使用if boolean_value,而不是if boolean_value == Trueif boolean_value is True。所以我认为如果这是官方的Python方式,我们Python的人也应该这样做。

问候。

答案 6 :(得分:0)

对于虚构的getattr函数,如果请求的属性始终可用但不是,则抛出错误。如果该属性是可选的,则返回None

答案 7 :(得分:0)

表示True,而不是None:

if foo:

表示错误,无:

if not foo:

答案 8 :(得分:0)

要确保的一件事是没有任何东西可以重新分配你的变量。如果它最终不是布尔值,依赖真实性将导致错误。动态类型语言中条件编程的美妙之处:)。

以下打印" "。

x = False
if x:
    print 'yes'
else:
    print 'no'

现在让我们改变 x

x = 'False'

现在声明打印" "因为这个字符串是真的。

if x:
    print 'yes'
else:
    print 'no'

但是,此声明正确输出" "。

if x == True:
    print 'yes'
else:
    print 'no'