Python断言语句中的比较

时间:2018-10-08 10:47:55

标签: python assert assertion

在检查了几个python开源项目之后,我发现了一些示例,其中相同的功能具有assert <>assert <> is True的测试用例。

我找不到有关在有条件或无条件的情况下使用assert语句的最佳实践的答案。

例如功能

def is_even(number):
    if number % 2 == 0:
        return True
    else:
        return False

可以通过这种方式进行测试

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

但也可以像

那样进行测试
assert is_even(6)

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

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

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

我看到thisthis这样的关于断言用法的问题,但似乎它们并未完全涵盖我的问题。

PEP 8 specification从另一面来看

  • 请勿使用==

    将布尔值与True或False进行比较
    Yes:   if greeting:
    No:    if greeting == True:
    Worse: if greeting is True:
    

但这还与assert的使用有关吗?

2 个答案:

答案 0 :(得分:4)

类似的代码

if a:
    return True
else:
    return False

还是不干净。应该将其写为return a,或者,如果需要布尔值(而不仅仅是一个稳定值),则应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,则假设结果过多。

因此,基线:不要将真实值与True进行比较。如果您对值的要求非常明确,例如“必须是布尔值,而不仅仅是行情波动”(这是极少数情况),则仅将结果值与True进行比较。

答案 1 :(得分:2)

assert完全像 if。它是一个关键字,后跟一个布尔表达式,它要求该表达式的计算结果为Trueassert expression仅在if expression成功的情况下才会成功。

鉴于此,您的问题有两个方面。前conditioncondition==True。这是风格问题。您无需写if condition==True:,而只需写if condition:。同样,没有理由写

assert is_even(6) == True

只要写

assert is_even(6)

相反。

第二个是condition==Truecondition is True。这不仅仅是样式问题。运行以下

if []==False:  # also: if not []
    print('false')

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

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

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

False是一个单例值,表示python解释器中只有一个 False对象,而所有错误的对象是< em>同一个对象。因此,使用is感觉不错(就像写if object is None被认为是一种好风格一样)。但是,python中存在虚假/真实值的概念:如果if condition为假,condition不一定为bool(condition),但不一定触发。这是自动完成的。在上面的示例中,空列表是虚假值。即bool([])的计算结果为False对象(同样,它只是一个)。因此,示例(1)成功,因为它已自动(内部)转换为类似于示例(2)的内容。但是,示例(3)不起作用,因为尽管空列表评估为false ,但并非 False。这是一个空列表。所以,总结一下例子

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

结束语:您给出示例

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

您提到<>可能是任何真实值。本着这种精神,相当于写

def is_even(number):
     return number % 2

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

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