1. 使用是否存在性能或代码维护问题 assert 作为标准代码的一部分而不是仅将其用于调试目的?

    assert x >= 0, 'x is less than zero'
    

    比更好或更差

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. 另外,有什么方法可以设置业务规则,例如 if x < 0 raise error 总是在没有 try/except/finally 所以,如果在整个代码中的任何时候 x 小于 0 会引发错误,就像您设置的那样 assert x < 0 在函数的开始处,函数内的任何位置 x 小于 0 会引发异常吗?

有帮助吗?

解决方案

当整个函数中 x 小于零时能够自动抛出错误。您可以使用 类描述符. 。这是一个例子:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

其他提示

断言应用于测试条件 永远不应该发生. 。目的是在程序状态损坏的情况下尽早崩溃。

异常应该用于可能发生的错误,并且 你几乎应该总是创建自己的异常类.


例如,如果您正在编写一个函数来从配置文件中读取数据 dict, ,文件中的格式不正确应该会引发 ConfigurationSyntaxError, ,虽然你可以 assert 你不会回来 None.


在你的例子中,如果 x 是通过用户界面或外部源设置的值,例外是最好的。

如果 x 仅由您自己的代码在同一程序中设置,请使用断言。

优化编译时删除“assert”语句. 。所以,是的,性能和功能都存在差异。

当编译时请求优化时,当前代码生成器不会为断言语句发出任何代码。- Python 2.6.4 文档

如果你使用 assert 实现应用程序功能,然后优化生产部署,您将受到“but-it-works-in-dev”缺陷的困扰。

Python优化-O-OO

的四个目的 assert

假设您与四位同事 Alice、Bernd、Carl 和 Daphne 一起处理 200,000 行代码。他们调用您的代码,您调用他们的代码。

然后 assert四个角色:

  1. 告知 Alice、Bernd、Carl 和 Daphne 您的代码的期望。
    假设您有一个处理元组列表的方法,并且如果这些元组不是不可变的,则程序逻辑可能会中断:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    这比文档中的等效信息更值得信赖,并且更容易维护。

  2. 告知计算机您的代码需要什么。
    assert 强制代码调用者采取正确的行为。如果您的代码调用Alices的代码和Bernd的代码调用您的代码,则没有 assert, ,如果该程序以Alices代码崩溃,Bernd可能会认为这是Alice的错,Alice进行了调查,可能认为这是您的错,您会调查并告诉Bernd实际上是他的。很多工作都丢掉了。
    有了断言,无论谁错了,他们都会很快就能看到这是他们的错,而不是您的错。爱丽丝、伯恩德和你们都会受益。节省大量时间。

  3. 告知您的代码的读者(包括您自己)您的代码在某个时刻取得了哪些成就。
    假设您有一个条目列表,每个条目都可以很干净(很好),也可以是Smorsh,Trale,Gullup或Twinkled(这都是不可接受的)。如果它是smosh的,那么它必须是unsmoshed的;如果它是真实的,那么它一定是歪曲的;如果它是咕噜咕噜的,那么它必须小跑(然后可能也有节奏);如果它闪烁,除了星期四之外,它必须再次闪烁。你明白了:这是很复杂的事情。但最终结果是(或应该是)所有条目都是干净的。正确的事情(TM)是总结清洁循环的效果为

    assert(all(entry.isClean() for entry in mylist))
    

    此陈述为每个试图了解什么的每个人都感到头疼 确切地 这是美妙的循环正在实现。这些人中最常见的可能就是你自己。

  4. 告诉计算机你的代码在某个时刻取得了什么成果。
    如果您曾经忘记在小跑之后加快需要的条目, assert 将节省您的一天,并避免您的代码破裂,亲爱的达芙妮(Dear Daphne)。

在我脑海里, assert文档(1和3)和保障(2和4)的两个目的同样有价值。
通知人们甚至可能是 更多的 比通知计算机有价值,因为它可以防止错误 assert 在任何情况下,旨在捕获(在情况1)和随后的许多错误。

除了其他答案之外,断言本身也会引发异常,但仅限于 AssertionErrors。从功利主义的角度来看,当您需要对捕获的异常进行细粒度控制时,断言不适合。

这种方法唯一真正错误的是,很难使用断言语句做出非常具有描述性的异常。如果您正在寻找更简单的语法,请记住您 也做这样的事情:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

另一个问题是,使用断言进行正常条件检查会很难使用 -O 标志禁用调试断言。

正如前面所说,当您的代码不应该达到某个点(这意味着那里存在错误)时,应该使用断言。我认为使用断言的最有用的原因可能是不变/前置/后置条件。这些在循环或函数的每次迭代开始或结束时必须为真。

例如,递归函数(2 个独立的函数,因此 1 个处理错误的输入,另一个处理错误的代码,因为很难与递归区分开)。如果我忘记写 if 语句,这会很明显地表明出了什么问题。

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

这些循环不变量通常可以用断言来表示。

英语单词 断言 这里的意思是 发誓, 确认, 承认. 。这并不意味着 “查看” 或者 “应该”. 。代表着 作为一名编码员正在制作 宣誓声明 这里:

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

如果代码正确,则禁止 单项赛事爆冷, 、硬件故障等, 没有任何断言会失败. 。这就是为什么程序对最终用户的行为不能受到影响。特别是,即使在以下情况下,断言也不会失败 特殊的计划条件. 。它只是永远不会发生。如果发生这种情况,程序员就应该受到惩罚。

有性能问题吗?

  • 请记住 “先让它发挥作用,然后才能使其快速发挥作用”.
    任何程序中很少有一部分与其速度相关。您始终可以剔除或简化 assert 如果事实证明这是一个性能问题,那么他们中的大多数就永远不会。

  • 务实:
    假设您有一个处理非空元组列表的方法,并且如果这些元组不是不可变的,则程序逻辑将中断。你应该写:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    如果您的列表往往为十个条目,这可能很好,但是如果它们有一百万个条目,可能会成为一个问题。但是,不用完全丢弃这项有价值的支票,而是可以将其降级到

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!
    

    价格便宜,但可能会抓住大部分 实际的 无论如何,程序错误。

有一个框架叫JBoss 流口水 对于进行运行时监控以断言业务规则的java,这回答了问题的第二部分。不过我不确定python是否有这样的框架。

断言是检查 -
1.有效条件,
2.有效的声明,
3.真正的逻辑;
的源代码。它不会使整个项目失败,而是发出警报,表明源文件中存在某些不合适的内容。

在示例 1 中,由于变量 'str' 不为 nul。因此不会引发任何断言或异常。

示例1:

#!/usr/bin/python

str = 'hello Pyhton!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Pyhton!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

在示例 2 中,var 'str' 为 nul。因此,我们可以通过以下方式使用户免于继续执行错误的程序 断言 陈述。

示例2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

当我们不想调试并意识到源代码中的断言问题时。禁用优化标志

python -O 断言语句.py
什么都不会打印

在 PTVS、PyCharm、Wing 等 IDE 中 assert isinstance() 语句可用于为一些不清楚的对象启用代码补全。

如果您正在处理依赖于的遗留代码 assert 正常运作,即使 它不应该, ,然后添加以下代码是一个快速修复,直到您有时间重构:

try:
    assert False
    raise Exception('Python Assertions are not working. This tool relies on Python Assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top