当我的程序遇到断言失败时,我不希望断言库执行导致程序进一步发展的事情,而不是没有断言失败。但这正是内置assert
似乎所做的:它引发了一个异常,它会释放锁。
例如,请考虑以下程序。
import threading
import time
lock = threading.Lock()
class Thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.start()
def run(self):
with lock:
time.sleep(0.2)
print "ASSERTION ON NEXT LINE"
assert False
# Were it not for the assert,
# This thread would hold the lock for a while longer.
time.sleep(1.0)
Thread()
time.sleep(0.1)
with lock:
print "*** Main Thread ***"
断言导致锁被释放,这导致主线程获得断言失败和回溯之间的锁定。结果,输出为:
ASSERTION ON NEXT LINE
*** Main Thread ***
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "so.py", line 14, in run
assert False
AssertionError
这是非常不受欢迎的,因为在追溯之前会打印*** Main Thread ***
。这很容易误导人们认为*** Main Thread ***
在生成异常之前获得了锁。
我知道我们可以编写自己的断言函数来调用os._exit()
而不是提出断言。我想知道的是,标准包装中是否已有类似的内容。
答案 0 :(得分:1)
如果您不想发布lock
,则必须在with lock:
内发现异常:
with lock:
try:
time.sleep(0.2)
print "ASSERTION ON NEXT LINE"
assert False
except Exception:
print "there was an exception"
while True:
pass
答案 1 :(得分:0)
如果我们使用assert并且失败则会引发断言错误。因为断言仅用于执行此操作(中断/停止流程)。我可以想到将它与Queue同步。
import time
import threading
from Queue import Queue
q = Queue()
# code here
class MyThread(threading.Thread):
def run(self):
# do stuff
print "ASSERTION ON NEXT LINE"
q.put(True)
# do other stuff
# code here
mt = MyThread()
mt.start()
try:
assert q.get()
finally:
mt.join()
答案 2 :(得分:0)
谢谢大家的贡献。我将主要以丹尼尔的答案为基础。我相信最好的答案取决于锁内有多少代码。如果你有一个很大的函数调用,那么
with lock:
try:
deep_complicated_function()
except Exception:
print "there was an exception"
print '\n'.join(traceback.format_stack()[:-1])
os._exit(1)
while True:
pass
是最好的,因为它使您有机会在一个构造中为大量异常情况提供处理程序。
然而,这对于一次性断言的输入太多,例如:
with lock:
quick_update()
assert property()
这些情况需要更方便的东西,例如:
def Assert(cond, msg = "Assertion failed."):
if not cond:
print msg
print '\n'.join(traceback.format_stack()[:-1])
os._exit(1)
这将停止该过程,这简化了调试(如问题中所讨论的)。要在nose
和其他测试工具中使用,请通过多处理API启动主程序,并在退出代码不为0时生成异常。