Is there a performance or code maintenance issue with using assert as part of the standard code instead of using it just for debugging purposes? Is assert x >= 0, 'x is less than zero' better or worse than if x < 0: raise Exception('x is less than zero') Also, is there any way to set a business rule like if x < 0 raise error that is always checked without the try/except/finally so, if at anytime throughout the code x is less than 0 an error is raised, like if you set assert x < 0 at the start of a function, anywhere within the function where x becomes less then 0 an exception is raised?
当前回答
如前所述,当您的代码should NOT到达某个点(意味着那里存在错误)时,应该使用断言。在我看来,使用断言最有用的原因可能是不变量/前置/后置条件。在循环或函数的每次迭代的开始或结束时,这些必须为真。
例如,一个递归函数(两个独立的函数,一个处理错误的输入,另一个处理错误的代码,因为它很难与递归区分开来)。如果我忘记写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
这些循环不变量通常可以用断言表示。
其他回答
是否存在性能问题?
Please remember to "make it work first before you make it work fast". Very few percent of any program are usually relevant for its speed. You can always kick out or simplify an assert if it ever proves to be a performance problem -- and most of them never will. Be pragmatic: Assume you have a method that processes a non-empty list of tuples and the program logic will break if those tuples are not immutable. You should write: def mymethod(listOfTuples): assert(all(type(tp)==tuple for tp in listOfTuples)) This is probably fine if your lists tend to be ten entries long, but it can become a problem if they have a million entries. But rather than discarding this valuable check entirely you could simply downgrade it to def mymethod(listOfTuples): assert(type(listOfTuples[0])==tuple) # in fact _all_ must be tuples! which is cheap but will likely catch most of the actual program errors anyway.
当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
assert的四个目的
假设您与四位同事Alice、Bernd、Carl和Daphne一起处理20万行代码。 他们喊你的代码,你喊他们的代码。
那么assert有四个角色:
Inform Alice, Bernd, Carl, and Daphne what your code expects. Assume you have a method that processes a list of tuples and the program logic can break if those tuples are not immutable: def mymethod(listOfTuples): assert(all(type(tp)==tuple for tp in listOfTuples)) This is more trustworthy than equivalent information in the documentation and much easier to maintain. Inform the computer what your code expects. assert enforces proper behavior from the callers of your code. If your code calls Alices's and Bernd's code calls yours, then without the assert, if the program crashes in Alices code, Bernd might assume it was Alice's fault, Alice investigates and might assume it was your fault, you investigate and tell Bernd it was in fact his. Lots of work lost. With asserts, whoever gets a call wrong, they will quickly be able to see it was their fault, not yours. Alice, Bernd, and you all benefit. Saves immense amounts of time. Inform the readers of your code (including yourself) what your code has achieved at some point. Assume you have a list of entries and each of them can be clean (which is good) or it can be smorsh, trale, gullup, or twinkled (which are all not acceptable). If it's smorsh it must be unsmorshed; if it's trale it must be baludoed; if it's gullup it must be trotted (and then possibly paced, too); if it's twinkled it must be twinkled again except on Thursdays. You get the idea: It's complicated stuff. But the end result is (or ought to be) that all entries are clean. The Right Thing(TM) to do is to summarize the effect of your cleaning loop as assert(all(entry.isClean() for entry in mylist)) This statements saves a headache for everybody trying to understand what exactly it is that the wonderful loop is achieving. And the most frequent of these people will likely be yourself. Inform the computer what your code has achieved at some point. Should you ever forget to pace an entry needing it after trotting, the assert will save your day and avoid that your code breaks dear Daphne's much later.
在我看来,assert的两个文档目的(1和3)和 保障措施(2和4)同样有价值。 告知人民甚至可能比告知计算机更有价值 因为它可以防止assert要捕捉的错误(在情况1中) 无论如何,接下来还有很多错误。
Assert是检查- 1. 有效条件, 2. 有效的表述, 3.真正的逻辑; 源代码。它不会让整个项目失败,而是会发出警报,提示源文件中有些地方不合适。
在例1中,因为变量'str'不是空的。因此不会引发任何断言或异常。
示例1:
#!/usr/bin/python
str = 'hello Python!'
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 Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py
在例2中,var 'str'为空。因此,我们可以通过assert语句来避免用户走在错误程序前面。
示例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 没有东西会被打印出来
这是一个悬而未决的问题,我有两个方面想涉及:何时添加断言以及如何编写错误消息。
目的
向初学者解释一下,断言是一种可能引发错误的语句,但您不会捕获它们。他们通常不应该被抚养,但在现实生活中,他们有时还是会被抚养。这是一个严重的情况,代码无法恢复,我们称之为“致命错误”。
其次,它是为了“调试目的”,虽然正确,但听起来非常轻蔑。我更喜欢“声明不变量,它永远不应该被违反”的提法,尽管它对不同的初学者有不同的作用……有些人“只是得到它”,而另一些人要么没有找到它的任何用途,要么取代正常的异常,甚至用它来控制流。
风格
在Python中,assert是语句,而不是函数!(记住assert(False, 'is true')不会引发。但是,先说一下:
何时以及如何编写可选的“错误消息”?
这实际上适用于单元测试框架,它通常有许多专用的方法来执行断言(assertTrue(条件),assertFalse(条件),assertEqual(实际的,预期的)等)。它们通常还提供了一种对断言进行评论的方法。
在一次性代码中,您可以不使用错误消息。
在某些情况下,没有什么可以添加到断言:
def垃圾场(东西): 屁 # ...
但除此之外,消息对于与其他程序员(有时是你代码的交互式用户,例如在Ipython/Jupyter等)的交流是有用的。
给他们信息,而不仅仅是泄露内部实现细节。
而不是:
assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'
写:
assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'
或者甚至:
assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'
我知道,我知道——这不是静态断言的情况,但我想指出消息的信息值。
消极还是积极的信息?
这可能是有争议的,但读到这样的东西让我很受伤:
assert a == b, 'a is not equal to b'
这是两个相互矛盾的东西。因此,每当我对代码库产生影响时,我就会通过使用“必须”和“应该”等额外的动词来明确我们想要什么,而不是说我们不想要什么。 断言a == b, 'a必须等于b'
然后,获取AssertionError: a must equal to b也是可读的,并且语句在代码中看起来是合乎逻辑的。此外,您可以在不读取回溯(有时甚至不可用)的情况下从中获得一些信息。
推荐文章
- 如何在交互式Python中查看整个命令历史?
- 如何显示有两个小数点后的浮点数?
- 如何用OpenCV2.0和Python2.6调整图像大小
- 在每个列表元素上调用int()函数?
- 当使用代码存储库时,如何引用资源的相对路径
- 如何在Flask-SQLAlchemy中按id删除记录
- 在Python中插入列表的第一个位置
- Python Pandas只合并某些列
- 如何在一行中连接两个集而不使用“|”
- 从字符串中移除前缀
- 代码结束时发出警报
- 如何在Python中按字母顺序排序字符串中的字母
- 在matplotlib中将y轴标签添加到次要y轴
- 如何消除数独方块的凹凸缺陷?
- 为什么出现这个UnboundLocalError(闭包)?