1.Python的logging模块中的error和exception区别**
共同点:
logging模块有6个级别,由低到高为NOTSET>>DEBUG>>INFO>>WARNING>>ERROR>>CRITICAL
,其实无论是error
还是exception
,它们的错误等级都是ERROR级别。
from loguru import logger
try:
port, minimum = 10, 12
assert port >= minimum
except Exception as e:
logger.error(e)
logger.exception(e)
运行结果为:
2022-03-04 23:52:13.925 | ERROR | __main__:<module>:11 -
2022-03-04 23:52:13.927 | ERROR | __main__:<module>:12 -
我们可以看到日志信息中,错误等级都是ERROR
不同点:
error级别的只输出错误的异常信息,而没有具体的错误堆栈信息,如果想要排查具体异常仅通过上面的异常message内容是远远不够的
exception级别的则不但会输出错误的异常信息,还会显示具体的错误堆栈信息,使得我们在排查问题的时候有更加明确的方向
2.assert与raise的区别
assert
的意义是在测试关键词后的条件(condition)为False时,程序自动崩溃并抛出AssertionError
的异常。常用形式为:
assert expression
等同于以下代码:
if _debug_:
if not expression:
raise AssertionError
assert expression1, expression2
等同于以下代码:
if _debug_:
if not expression1:
raise AssertionError(expression2)
以上两段代码中的_debug_和AssertionError都代表的是Python中内建的变量。通常在Python中_debug_在普通情况下均为True。只有在python启动时加上-o选项(生成优化后的*.pyo文件),_debug_为False。所以当程序以优化模式编译后,assert声明并不会被执行。
以下两段代码,大家可以仔细体会下他们的区别:
assert写法
from loguru import logger
try:
port, minimum = 10, 12
assert port >= minimum
except Exception as e:
logger.error(e)
logger.exception(e)
返回结果为:
2022-03-05 00:10:45.255 | ERROR | __main__:<module>:11 -
2022-03-05 00:10:45.256 | ERROR | __main__:<module>:12 -
Traceback (most recent call last):
File "/Users/lijinze/anaconda3/envs/py36/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
└ ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7fb5d873f828>, origin='...
*****
assert port >= minimum
│ └ 12
└ 10
AssertionError: assert port >= minimum
raise写法
from loguru import logger
try:
port, minimum = 10, 12
if port < minimum:
raise RuntimeError('出错了')
# raise ValueError('出错了')
except Exception as e:
logger.error(e)
logger.exception(e)
返回结果为:
2022-03-05 00:10:45.255 | ERROR | __main__:<module>:11 -
2022-03-05 00:10:45.256 | ERROR | __main__:<module>:12 -
Traceback (most recent call last):
File "/Users/lijinze/anaconda3/envs/py36/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
└ ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7fb5d873f828>, origin='...
*****
assert port >= minimum
│ └ 12
└ 10
RuntimeError: 出错了
区别: assert
是用来确保程序的正确性,而不是用来矫正或者指示一些不可预知的错误的发生。简单来说是程序员debug
的工具,有无这段程序,不应影响程序的功能执行,但对程序正确性有影响。 raise
是用来检查用户输入是否正确,指示程序违反了预设的条件。
python文件的格式除了.py还有.pyc/.pyo,后两张需要经过编译再运行,其中.pyo是经过优化后编译的二进制文件,可以增加程序的稳定性,隐藏源码。而在.pyo格式的版本中是不对assert进行编译的,这也是不用assert 作为检查输入参数合法性的原因之一。
Tips:
RuntimeError
,ValueError
与AssertionError
都是error类
3.多线程异常处理模板
def exception_warpper(func):
functools.wraps(func)
def inner(*args, **kwargs):
func_name = ''
ret = None
try:
func_name = func.__name__
ret = func(*args, **kwargs)
except Exception as e:
logger.exception(e)
Alarm.msg('exception, {}'.format(func_name))
return ret
return inner
# 多线程业务逻辑模块
crawler_dir = os.path.join(spider_dir, 'crawler', 'crawler_*.py')
with ThreadPoolExecutor(max_workers=self.max_worker) as pool:
futures = set()
for cls_path in glob.glob(crawler_dir):
imp_cls = self._load_class(
cls_path,
'spider.crawler',
'CrawlerImpl'
)
if imp_cls is not None:
cls_obj = imp_cls()
job = pool.submit(exception_warpper(cls_obj.crawl))
futures.add(job)
else:
logger.error('spider:{} load fail!', cls_path)
for job in as_completed(futures):
result = job.result()
if result:
self.crawler_result_list.append(result)
logger.info('crawl:{}, {}', result.name, result.url)
else:
logger.warning('crawl_result is null')