一、Python中的异常Exception捕获以及python2与python3的区别
Python开发的时候经常会碰到两类错误,语法错误SyntaxError: invalid syntax 和异常Exception。在语法没有问题的前提下在运行期检测到的错误被称为异常,大多数的异常都不会被程序处理,都以错误信息的形式展现出来,且异常以不同的类型出现,这些类型都作为信息的一部分打印出来,如可能报的除数为0的错误ZeroDivisionError;比如使用assert(断言)用于判断一个表达式当为false的时候会触发抛出一个AssertionError异常等等。
异常捕捉可以使用try/except语句,先执行try 子句,如果没有异则忽略except子句,如发生异常,会直接去匹配对应名称的except后执行,如果没有匹配的except,这个异常将会传递给上层的try 中并会在finally子句执行后被抛出。出错。一个try语句可能包含多个except子句,分别来处理不同的特定的异常。
除了try/except形式外,还有一种try/except...else..finally 形式,else子句将在try子句没有发生任何异常的时候执行,实际没有什么用处,因为其效果和不使用else一个样。而finally 语句则是无论是否发生异常都将执行最后的代码。下面这个例子能完美解释上面的这些规则:
>>> def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
#只执行finally
>>> divide(2, 1)
result is 2.0
executing finally clause
#抛出异常并执行finally
>>> divide(2, 0)
division by zero!
executing finally clause
#抛出异常未捕获然后先执行finally,最后报错
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
上面最后报的详细错误也可以手动捕获处理,这时就需要使用traceback模块,使用traceback.print_exc()打印异常信息到标准错误,就像没有捕获一样的展示,也可以使用traceback.format_exc()提取错误输出为字符串,从而可以自定义输出。
关于Python3与Python2的Exception,有两个变化:
1)Python3中try/except语句中不支持使用逗号分隔 Exception和e,
Python3中try/except语句中不支持使用逗号分隔 Exception和e,,必须用as关键词进行替换(python2中两种都可以)。
2)Python3中Exception类没有message成员变量,
Python3中Exception类没有message成员变量,不过可以直接print(e)即可以打印错误信息,或者转为str进行其它拼接处理。
示例及说明如下:
try:
print([1,2,3] + 1)
#python3中不能使用except Exception, e:
except Exception as e:
#repr打印出包含对象信息的内容如
#TypeError('can only concatenate list (not "int") to list')
print(repr(e))
#等同于:python2中的e.message,但python3中不能使用print(e.message)
print(str(e))
print 'e.message:\t', e.message
print 'traceback.print_exc():'; traceback.print_exc()
print 'traceback.format_exc():\n%s' % traceback.format_exc()
#如下示例,使用traceback打印和捕获错误展示。
import traceback
try:
a = [1,2,3]
print(a+1)
except Exception as e:
traceback.print_exc()
print("-"*20)
print('traceback.format_exc():\n%s' % traceback.format_exc())
print("="*20)
另外python2和python3中都可以使用sys.exc_info()方法获取正在处理的异常信息,即except子句正在处理的异常,其返回一个tuple类型的三元组(exc_type, exc_value, exc_traceback),其中:
exc_type为获取到的异常类型;
exc_value为该异常类型对象;
exc_traceback为一个 traceback 对象,包含异常最初发生的调用栈信息。
#如下示例使用sys.exc_info()方法获取异常
try:
a = [1,2,3]
print(a+1)
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
print(exc_type)
print(exc_value)
print(exc_traceback)
#以上示例中会输出错误信息:
<class 'TypeError'>
can only concatenate list (not "int") to list
<traceback object at 0x0000024110A03D80>
二、Fastapi框架提取所有的route路由以做后台权限控制的实现
在做项目的权限控制时,为了实现自动化扩展权限控制,我们习惯将控制器方法作为一个权限标识,然后根据帐户的权限中是否存在这么一项路由以作为其是否能管理这项操作。这是一个简单且易维护的功能实现方法,之前见过一套教学系统,可能功能也比较庞大,其在做权限的时候用的一套复杂的配置文件,非常烦人。
使用上面的方法的关键是要分离后台程序中的所有路由器方法,并过滤一些非权限项的路由,比如退出方法,然后添加进数据库表,再将角色和权限进行一对多联系起来。之后只需要将用户和角色进行关联,即能实现自由授予权限。
使用Fastapi框架开发的管理后台,也可以轻松实现上面的权限控制,使用如下方法可以实现提取所有的路由方法。在处理所有的路由的文件里我们需要实例化APIRouter,并将各个路由中的方法通过include_router加入APIRouter的实例中。如下:
routerObj = APIRouter()
routerObj.include_router(模块,tag标签,prefix前缀等)
因此我们可以使用这个routerObj来提取所有的方法。如下:
#引入routerObj
import routerObj
@router.get("/get_all_fun", summary="get_all_function")
async def get_all_fun():
data = routerObj.routes
for r in data:
ritem = r.__dict__
print(ritem['path'])
print(ritem['tags'])
print(ritem['summary'])
上面的方法中提取routerObj对象的routes对象,其包括了整个项目的路由信息,object.__dict__将其转换为字典,然后就可以把fastapi模块中定义的@router.get/post等方法全部提取打印出来,并得到summary,这样就可以拿到权限应该有的权限名称以权限路由,记录数据库,然后在管理后台的用户验证逻辑程序中判断用户是否有这个权限(即用户请求的路由是否在给其分配的角色权限列表中)。