断言是什么意思?它是如何使用的?


当前回答

断言是什么意思?它是如何使用的?

这里有很好的答案,但不是问题的第二部分。尽管有多年的实践经验,但我直到最近才明白断言的目的。

其他人已经解释了如何使用assert,所以我非常简短。下面是它的用法:

assert condition, "error message"

不要使用圆括号,assert是关键字,不是函数。

assert (condition, "error message")  # wrong: this never fails!

这里给出了如何使用assert的一个很好的解释:http://wiki.c2.com/?WhatAreAssertions assert的目的是在代码中声明不变量。不变式是一种永远不应该违反的条件,除非代码中存在错误。把它们看作是可执行的文档。这与面向对象编程如何封装来自外部世界的代码密切相关。

简单地说:对于其他开发人员,您应该在代码中像使用注释一样使用断言。但它比注释要好,“注释”实际上是在调试模式下检查的!如果删除断言后,您的程序不能正常工作,那么您使用错误。事实上,如果你打开优化(Python -O), Python将忽略所有的断言。所以不要依赖他们。特别是,不要使用断言来验证用户输入。而是引发异常。

这里有一个很好的例子来把它们联系在一起。让我们假设您希望在代码中有一个特殊的数字类,它表示称为PositiveInt的正整数。你为什么想要那个?有许多函数使用正整数作为参数。通过在代码中使用PositiveInt,您不必在每个函数中反复检查输入是否有效。它由PositiveInt保证。粗略的实现如下所示

class PositiveInt(int):
    # int is immutable, so we have to override new and not init
    def __new__(cls, value):
        if value <= 0:
            raise ValueError(f"{value} is not positive")
        assert value > 0, "value must be positive"
        return super(PositiveInt, cls).__new__(cls, value)   

如你所见,我用了两个if…:提高……用于输入验证和函数末尾的断言。这似乎是多余的,但仅在这个微不足道的示例中!假设函数稍微长一些,也更复杂一些,因此您是否正确地验证了输入并不明显。末尾的断言确保检测到验证代码中的错误。它还使另一个程序员更清楚地了解验证代码的意图,而不是简单的注释。

总之:像使用注释一样使用assert。到处使用!它很便宜,如果它成为用户的性能问题,你可以在发行版中使用python -O关闭它。

其他回答

如果assert关键字后面的代码为False, Python中的assert关键字将引发AssertionError。如果没有,它继续什么都没有发生。

示例1:

a = 5
b = 6

assert a == b

输出:

AssertionError

这是因为,很明显,a不等于b。 如果你想在代码中引发一个异常,这是特别有用的。

def get_dict_key(d, k):
    try:
        assert k in d
        return d[k]
    except Exception:
        print("Key must be in dict.")

上面的示例实际上是无用的,但是请记住,它主要用于调试目的,因此您可以跟踪错误。

assert语句几乎存在于每一种编程语言中。它有助于在程序的早期(原因很清楚的时候)检测问题,而不是在稍后作为其他操作的副作用检测问题。他们总是期待一个真实的条件。

当你这样做的时候:

assert condition

您告诉程序测试该条件,如果为假,则立即触发错误。

在Python中,assert表达式等价于:

if __debug__:
    if not <expression>: raise AssertionError

你可以使用扩展表达式来传递一个可选的消息:

if __debug__:
    if not (expression_1): raise AssertionError(expression_2)

在Python解释器中试试:

>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

在使用它们之前有一些注意事项,主要是针对那些认为在assert和if语句之间切换的人。使用assert的目的是在某些情况下,当程序验证一个条件并返回一个值时,应该立即停止程序,而不是采取其他方法来绕过错误:

1. 括号

您可能已经注意到,assert语句使用了两个条件。因此,不要用圆括号把它们括起来作为一个明显的建议。如果你这样做:

assert (condition, message)

例子:

>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

你将使用(condition, message)运行断言,它表示一个元组作为第一个参数,这是因为Python中的非空元组总是True。但是,你可以单独做,没有问题:

assert (condition), "message"

例子:

>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.

2. 调试的目的

如果你想知道什么时候使用assert语句。举一个现实生活中的例子:

*当你的程序倾向于控制用户输入的每个参数时:

def loremipsum(**kwargs):
    kwargs.pop('bar') # return 0 if "bar" isn't in parameter
    kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
    assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())

*另一种情况是在数学中,0或非正作为某个方程的系数或常数:

def discount(item, percent):
    price = int(item['price'] * (1.0 - percent))
    print(price)
    assert (0 <= price <= item['price']),\
            "Discounted prices cannot be lower than 0 "\
            "and they cannot be higher than the original price."

    return price

*甚至是一个简单的布尔实现的例子:

def true(a, b):
    assert (a == b), "False"
    return 1

def false(a, b):
    assert (a != b), "True"
    return 0

3.数据处理或数据验证

最重要的是不要依赖assert语句来执行数据处理或数据验证,因为该语句可以在Python初始化时使用- o或- oo标记(分别表示值1、2和0(默认值))或PYTHONOPTIMIZE环境变量关闭。

价值1:

* assert被禁用;

*字节码文件使用.pyo而不是.pyc扩展名生成;

* sys.flags.optimize设置为1 (True);

*和,__debug__被设置为False;

值2:禁用一个东西

*文档字符串被禁用;

因此,使用assert语句来验证一种预期的数据是极其危险的,甚至意味着存在一些安全问题。然后,如果你需要验证一些权限,我建议你提出AuthError代替。作为有效的前置条件,assert通常由程序员在不与用户直接交互的库或模块上使用。

如果assert后的语句为真,则程序继续执行,但如果assert后的语句为假,则程序报错。就这么简单。

例如:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError

注意括号。正如在其他回答中指出的那样,在Python 3中,assert仍然是一个语句,因此通过与print(..)类比,可以推断出assert(..)或raise(..),但不应该这样做。

这是错误的:

assert(2 + 2 == 5, "Houston we've got a problem")

这是正确的:

assert 2 + 2 == 5, "Houston we've got a problem"

第一个不能工作的原因是bool((False,“Houston we've got a problem”))的值为True。

在assert(False)语句中,这些只是在False周围的多余圆括号,对其内容求值。但是使用assert(False),圆括号现在是一个元组,而非空元组在布尔上下文中的计算结果为True。

Python assert基本上是一种调试辅助工具,用于测试代码内部自检的条件。 当代码进入不可能的边缘情况时,Assert使调试变得非常容易。断言检查那些不可能的情况。

假设有一个函数计算商品折扣后的价格:

def calculate_discount(price, discount):
    discounted_price = price - [discount*price]
    assert 0 <= discounted_price <= price
    return discounted_price

这里,discounted_price永远不能小于0并且大于实际价格。因此,如果上述条件被违反,assert将引发断言错误,这有助于开发人员识别发生了不可能的事情。

希望能有所帮助。