3 回答
每当您编写代码时,都会有一些关注点的平衡:性能、可读性、正确性、可扩展性、可维护性等。不幸的是,通常不可能同时在每个方向上改进代码。例如,快速的内容可能不那么可读。
在 Python 中受到鼓励的原因之一try..except
是因为您通常无法预料到您的代码可能会被使用的所有方式,因此与其检查是否存在特定条件,更一般的做法是捕获任何特定类别的错误可能会出现。因此try..except
可能会使您的代码更可重用。
但是,如果经常到达该子句,这也是try..except
很慢的。except
有没有办法对该块进行编码,以便不会引发异常并使用 try..except 来捕获不太频繁的条件?
或者如果没有,为了效率,你可以选择不使用try..except。编程中几乎没有硬性规定。你必须根据你的关注点来选择你的方式。
如果您尝试优化此功能以提高速度,您应该关注可能成为实际瓶颈的地方。您的三个数据库查询,每一个都会导致操作系统进行上下文切换,几乎可以肯定比捕获异常要长一个数量级。如果您想尽可能快地编写代码,请首先将所有三个数据库查询合并为一个:
auth_objects = UserSocialAuth.objects.filter(user=self, provider__in=('facebook', 'foursquare', 'twitter'))
然后循环遍历对象。如果这provider__in
三个提供者是数据库中唯一的提供者,则可能不需要过滤器。
确实,捕获异常的成本适中(请参阅下面的一些时间),并且您不希望在程序的瓶颈中使用它,但是在您给出的示例中,捕获异常将是很小的一部分与Model.objects.get
必须构建 SQL 查询、将其传输到数据库服务器并等待数据库报告没有此类对象的调用进行比较的调用。
一些示例时间。函数f2
抛出和捕获异常,同时f1
实现相同的功能而不使用异常。
d = dict()
def f1():
if 0 in d: return d[0]
else: return None
def f2():
try: return d[0]
except KeyError: return None
>>> timeit(f1)
0.25134801864624023
>>> timeit(f2)
2.4589600563049316
并f3
尝试通过 Django 的 ORM 从数据库(在同一台机器上运行)获取一个不存在的对象:
def f3():
try:
MyModel.objects.get(id=999999)
except MyModel.DoesNotExist:
pass
这需要大约 400 倍的时间f2
(以至于我不想等待默认number=1000000
迭代完成):
>>> timeit(f3, number=1000)
1.0703678131103516