Python断言语句中的比较

Comparison in Python assert statement

本问题已经有最佳答案,请猛点这里访问。

在检查了几个python开源项目之后,我找到了相同函数具有assert <>assert <> is True的测试用例的示例。

而且我无法找到有关使用assert语句的最佳实践的答案,无论是否有完整条件。

例如功能

1
2
3
4
5
def is_even(number):
    if number % 2 == 0:
        return True
    else:
        return False

可以这样测试

1
2
assert is_even(6) is True
assert is_even(6) == True

但它也可以测试

1
assert is_even(6)

如果函数is_even将被更改,我在这里看到问题原因

1
2
3
4
5
def is_even(number):
    if number % 2 == 0:
        return <>
    else:
        return False

其中<>可以在任何数字(0除外)或非空字符串上更改 - 最后一次测试将通过。 但这将是另一个功能。

我看到了这个以及关于断言用法的问题,但似乎它们并没有完全覆盖我的问题。

另一方面,PEP 8规范有这样的例子

  • 不要使用==将布尔值与True或False进行比较

    1
    2
    3
    Yes:   if greeting:
    No:    if greeting == True:
    Worse: if greeting is True:

但是它也是关于assert的用法吗?


代码就像

1
2
3
4
if a:
    return True
else:
    return False

反正是不洁净的。它应该写成return a,或者,如果需要bool(而不仅仅是一个条件值),return bool(a)

如果你使用v == Truev is True完全符合这种情况。第一个将检查值是否等于值True。值是否为此,也取决于此值的类(1 == True为true,1.0 == True为true,但1j == True为false)。

如果你使用is进行比较,那么你绝对清楚地表明你接受了值True而没有别的。

但是,在大多数情况下,我认为仅仅声明assert f(x)将是语义上正确的事情。例如,对于像assert is_in_rectangle(point)这样的断言。将其拼写为assert is_in_rectangle(point) == Trueassert is_in_rectangle(point) is True将是错误的,因为任何不完整的值(例如[ 1 ])都应该足够了。检查显式True作为结果将假设太多。

所以,基线:不要将truish值与True进行比较。如果您对值有非常具体的要求,例如"必须是一个bool,而不仅仅是truish"(这是一种罕见的情况),则仅将结果值与True进行比较。


assertif完全相同。它是一个关键字,后跟一个布尔表达式,它要求表达式求值为True。当且仅当if expression成功时,语句assert expression才会成功。

鉴于此,您的问题有两个方面。第一个condition vs condition==True。这是一种风格问题。你不写if condition==True:,只是if condition:。同样,没有理由写

1
assert is_even(6) == True

写吧

1
assert is_even(6)

代替。

第二个是condition==True vs condition is True。这不仅仅是风格问题。运行以下

1
2
3
4
5
6
7
8
if []==False:  # also: if not []
    print('false')

if bool([]) is False:
    print('false')

if [] is False:
    print('false')

将打印示例(1)和(2),但示例(3)将不打印。

False是单例值,这意味着python解释器中只有一个False对象,并且所有虚假对象都是同一个对象。因此,使用is感觉正确(就像它被认为是写if object is None的好风格)。但是,python中存在falsy / truthy值的概念:如果condition为false,则if condition不一定触发,但如果bool(condition)为false。这是自动完成的。在上面的示例中,空列表是一个虚假值。即bool([])评估False对象(再次,只有一个)。因此,示例(1)成功,因为它自动转换(内部)类似于示例(2)。但是,示例(3)不起作用,因为尽管空列表的计算结果为false,但它不是False。这是一个空列表。所以,总结你的例子

1
2
3
if greeting: # good style, and it works
if greeting==True: # bad style, redundant, but it still works
if greeting is True: # misleading. does a different thing than it seems to do. avoid it

结束评论:你举例说明

1
2
3
4
5
def is_even(number):
    if number % 2 == 0:
        return <>
    else:
        return False

你提到<>可能是任何真正的价值。本着这种精神,它等同于写作

1
2
def is_even(number):
     return number % 2

因为它会返回非零(真实)或零(虚假)。但是,不要这样做。名为is_even的函数的用户希望函数返回TrueFalse,而不是整数。您不知道该用户如何使用您的代码(例如,可能将其发送到数据库,或者需要真正布尔值的Web服务)。所以最好返回一个布尔值。因此,函数的最短和最安全的形式是写

1
2
def is_even(number):
    return bool(number % 2)