回答(13)
2 years ago
当x在整个函数中变得小于零时能够自动抛出错误 . 你可以使用class descriptors . 这是一个例子:
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 "", line 1, in
File "my.py", line 7, in __set__
raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero
2 years ago
断言应该用于测试不应该发生的条件 . 目的是在程序状态损坏的情况下尽早崩溃 .
异常应该用于可能发生的错误,并且 you should almost always create your own Exception classes .
例如,如果您正在编写一个函数以从配置文件读取到 dict ,则文件中的格式不正确应该引发 ConfigurationSyntaxError ,而您可以 assert 表示您不打算返回 None .
在您的示例中,如果 x 是通过用户界面或外部源设置的值,则最好是例外 .
如果 x 仅由您自己的代码在同一程序中设置,请使用断言 .
2 years ago
"assert" statements are removed when the compilation is optimized . 所以,是的,有性能和功能差异 .
当在编译时请求优化时,当前代码生成器不会为assert语句发出任何代码 . - Python 2.6.4 Docs
如果您使用 assert 来实现应用程序功能,然后将部署优化到 生产环境 ,您将受到"but-it-works-in-dev"缺陷的困扰 .
2 years ago
断言的四个目的
假设您与四位同事Alice,Bernd,Carl和Daphne一起处理了200,000行代码 . 他们调用你的代码,你调用他们的代码 .
然后 assert 有 four roles :
Inform Alice, Bernd, Carl, and Daphne what your code expects.
假设您有一个处理元组列表的方法,如果这些元组不是不可变的,程序逻辑可能会中断:
def mymethod(listOfTuples):
assert(all(type(tp)==tuple for tp in listOfTuples))
这比文档中的等效信息更可靠,更易于维护 .
Inform the computer what your code expects.
assert 强制执行代码调用者的正确行为 . 如果你的代码调用Alices 's and Bernd' s代码调用你的,那么没有 assert ,如果程序在Alices代码崩溃,Bernd可能会认为这是Alice的错,Alice调查并可能认为这是你的错,你调查并告诉Bernd它在事实上他的 . 失去了很多工作 .
有了断言,无论谁接到错误的电话,他们很快就会发现这是他们的错,而不是你的错 . 爱丽丝,伯恩德,你们都受益匪浅 . 节省了大量的时间 .
Inform the readers of your code (including yourself) what your code has achieved at some point.
假设你有一个条目列表,每个条目都可以是干净的(这很好),或者它可以是smorsh,trale,gullup或者闪烁(这些都是不可接受的) . 如果它必须是baludo;它必须是baludoed;如果它闪烁,它必须再次闪烁,除了星期四 . 你明白这个想法:这很复杂 . 但最终结果是(或应该)所有条目都是干净的 . Right Thing(TM)要做的是总结清洁循环的效果
assert(all(entry.isClean() for entry in mylist))
对于每个试图理解精彩循环实现的确切内容的人来说,这个陈述让人头疼 . 而这些人中最常见的可能就是你自己 .
Inform the computer what your code has achieved at some point.
如果您在小跑之后忘记调整需要它的条目, assert 将节省您的一天,并避免您的代码打破亲爱的Daphne's晚了 .
在我看来,文件(1和3)和保障(2和4)的两个目的同样有 Value .
告知人们甚至可能比告知计算机更有 Value ,因为它可以防止出现的错误(案例1)以及随后的大量错误 .
2 years ago
除了其他答案之外,断言本身会抛出异常,但只会抛出AssertionErrors . 从功利主义的角度来看,当你需要精细控制你捕获的异常时,断言不适合 .
2 years ago
_606519很难用assert语句做出非常具有描述性的异常 . 如果您正在寻找更简单的语法,请记住您也可以这样做:
class XLessThanZeroException(Exception):
pass
def CheckX(x):
if x < 0:
raise XLessThanZeroException()
def foo(x):
CheckX(x)
#do stuff here
另一个问题是使用assert进行正常条件检查是因为它很难使用-O标志禁用调试断言 .
2 years ago
如前所述,当您的代码不应达到某一点时,应使用断言,这意味着存在错误 . 我可以看到使用断言的最有用的原因可能是一个不变/前/后条件 . 这些在循环或函数的每次迭代的开始或结束时必须是真的 .
例如,递归函数(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
这些循环不变量通常可以用断言表示 .
2 years ago
英语单词 assert 在这里用于 swear , affirm , avow . 这并不意味着"check"或"should be" . 这意味着你作为一名程序员在这里制作一个 sworn statement :
# 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
如果代码正确,则禁止Single-event upsets,硬件故障等, no assert will ever fail . 这就是为什么程序对最终用户的行为不得受到影响的原因 . 特别是,即使在 exceptional programmatic conditions 下,断言也不会失败 . 它永远不会发生 . 如果它发生了,那么程序员应该为之奋斗 .
2 years ago
是否存在性能问题?
请记住 "make it work first before you make it work fast" .
任何程序的百分之几通常与其速度相关 . 如果它被证明是一个性能问题,你总是可以踢出或简化 assert - 而且大部分都不会 .
Be pragmatic :
假设您有一个处理非空元组列表的方法,如果这些元组不是不可变的,程序逻辑将会中断 . 你应该写:
def mymethod(listOfTuples):
assert(all(type(tp)==tuple for tp in listOfTuples))
如果您的列表往往长达十个条目,这可能很好,但如果它们有一百万个条目,它可能会成为一个问题 . 但不是完全丢弃这个有 Value 的支票,你可以简单地将其降级为
def mymethod(listOfTuples):
assert(type(listOfTuples[0])==tuple) # in fact _all_ must be tuples!
这很便宜,但无论如何都可能会捕获大部分实际程序错误 .
2 years ago
有一个名为JBoss Drools的框架,用于执行运行时监控以断言业务规则,该问题回答了问题的第二部分 . 但是,我不确定是否有这样的python框架 .
2 years ago
断言是检查 -
1. the valid condition, 2. the valid statement, 3. true logic; 源代码 . 它不会使整个项目失败,而是会在源文件中发出不适合的警报 .
在示例1中,因为变量'str'不是nul . 因此,不会引发任何断言或异常 .
Example 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 . 所以我们通过 assert 语句来保存用户免于错误的程序 .
Example 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 assertStatement.py
什么都不会打印
2 years ago
在诸如PTVS,PyCharm之类的IDE中,Wing assert isinstance() 语句可用于为某些不清楚的对象启用代码完成 .
2 years ago
如果您正在处理依赖 assert 正常运行的遗留代码,即使it should not,那么添加以下代码是一个快速修复,直到您找到时间重构:
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