简体   繁体   English

避免例外?

[英]Avoid exceptions?

This particular example relates to Django in Python, but should apply to any language supporting exceptions: 此特定示例与Python中的Django有关,但应适用于支持例外的任何语言:

try:
    object = ModelClass.objects.get(search=value)
except DoesNotExist:
    pass

if object:
    # do stuff

The Django model class provides a simple method get which allows me to search for one and only one object from the database, if it finds more or less it raises an exception. Django模型类提供了一种简单的方法get ,它使我可以从数据库中搜索一个并且只有一个对象,如果发现或多或少会引发异常。 If can find zero or more with an alternative filter method, which returns a list: 如果可以使用替代过滤器方法找到零个或多个,则返回一个列表:

objects = ModelClass.objects.filter(search=value)
if len(objects) == 1:
    object = objects[0]
    # do stuff

Am I overly averse to exceptions? 我是否过度反对例外? To me the exception seems a little wasteful, at a guess, a quarter-to-a-half of the time will be 'exceptional'. 在我看来,这种例外似乎有些浪费,据猜测,四分之一至二分之一的时间将是“例外”。 I'd much prefer a function that returns None on failure. 我更希望在失败时返回None的函数。 Would I be better to use Django's filter method and process the list myself? 我会更好地使用Django的filter方法并自己处理列表吗?

Believe it or not, this actually is an issue that is a bit different in each language. 信不信由你,这实际上是一个问题,每种语言都有所不同。 In Python, exceptions are regularly thrown for events that aren't exceptional by the language itself. 在Python中,通常会针对语言本身并非异常的事件引发异常。 Thus I think that the "you should only throw exceptions under exceptional circumstances" rule doesn't quite apply. 因此,我认为“仅应在特殊情况下引发异常”规则并不适用。 I think the results you'll get on this forum will be slanted towards that point of view though, considering the high number of .Net programmers (see this question ) for more info on that). 考虑到大量的.Net程序员(请参阅此问题 )以获取更多信息,我认为您在该论坛上获得的结果将倾向于该观点。

At a very minimum, I'd better not catch anyone who sticks to that rule ever using a generator or a for loop in Python (both of which involve throwing exceptions for non-exceptional circumstances). 至少,我最好不要在Python中使用生成器或for循环来抓住那些坚持该规则的人(这两者都涉及在非异常情况下引发异常)。

There's a big schism in programming languages around the use of exceptions. 编程语言在使用异常方面有很大的分歧。

  • The majority view is that exceptions should be exceptional . 大多数人认为例外应该是例外 In most languages with exceptions, transfer of control by exception is considerably more expensive than by procedure return, for example. 例如,在大多数带有例外的语言中,通过例外进行的控制转移比通过过程返回进行的转移要昂贵得多。

  • There is a strong minority view that exceptions are just another control-flow construct, and they should be cheap. 少数派强烈认为例外是另一个控制流构造,它们应该便宜。 The Standard ML of New Jersey and Objective Caml compilers subscribe to that view. 新泽西Standard MLObjective Caml编译器都支持该视图。 If you have cheap exceptions you can code some fancy backtracking algorithms in ways that are more difficult to code cleanly using other mechanisms. 如果您有便宜的例外情况,则可以采用一些难以使用其他机制进行干净编码的方式来编写一些奇特的回溯算法。

I've seen this debate repeated many times for new language designs, and almost always, the winner decides that exceptions should be expensive and rare. 我已经看到针对新语言设计的辩论多次进行,并且几乎总是赢家认为例外应该是昂贵且罕见的。 When you care about performanced, you'd be wise to program with this in mind. 当您关心表现时,明智的做法是牢记这一点。

The clue is in the name - exceptions should be exceptional. 线索就是名字-例外应该是例外。

If you always expect the item will exist then use get , but if you expect it not to exist a reasonable proportion of the time (ie it not existing is an expected result rather than an exceptional result) then I'd suggest using filter . 如果您始终希望该项目存在,请使用get ,但是如果您希望它在一段时间内不存在(即不存在是预期的结果,而不是例外的结果),则建议使用filter

So, seeing as you indicated that between 1 in 2 and 1 in 4 are expected not to exist, I'd definitely write a wrapper around filter , as that's definitely not an exceptional case. 因此,正如您所指出的那样,期望不存在1比2和1比4之间的问题,我肯定会在filter周围写一个包装filter ,因为这绝对不是例外。

The answer will depend on the intent of the code. 答案将取决于代码的意图。 (I'm not sure what your code sample was meant to do, the pass in the exceptional case is confusing, what will the rest of the code do with object variable to work with?) (我不确定您的代码示例打算做什么,在特殊情况下的传递会造成混淆,其余代码将如何与object变量一起使用?)

Whether to use exceptions or to use a method which treat the case as non-exceptional is a matter of taste in many cases. 在许多情况下,是否使用例外或使用将案件视为非例外的方法都是一个问题。 Certainly if the real code in the except clause is as complicated as the filter method you'd have to use to avoid the exception, then use the filter method. 当然,如果except子句中的实际代码与为避免异常而必须使用的过滤器方法一样复杂,请使用过滤器方法。 Simpler code is better code. 简单的代码就是更好的代码。

I agree with the other answer but I wanted to add that exception passing like this is going to give you a very noticeable performance hit. 我同意其他答案,但我想添加这样的异常传递,这将给您带来非常明显的性能损失。 Highly recommended that you check to see if the result exists (if that's what filter does) instead of passing on exceptions. 强烈建议您检查结果是否存在(如果这是过滤器的作用),而不要传递异常。


Edit: 编辑:

In response to request for numbers on this, I ran this simple test... 为了响应对此的要求,我进行了这个简单的测试...

import time

def timethis(func, list, num):
  st=time.time()
  for i in xrange(0,1000000):
    try:
      func(list,num)
    except:
      pass
  et = time.time()
  print "Took %gs" % (et-st)

def check(list, num):
  if num < len(list):
    return list[num]
  else:
    return None

a=[1]
timethis(check, a, 1)
timethis(lambda x,y:x[y], a, 1)

And the output was.. 和输出是..

Took 0.772558s
Took 3.4512s

HTH. HTH。

Aversion to excpetions is a matter of opinion - however, if there's reason to believe that a function or method is going to be called many times or called rapidly, exceptions will cause a significant slowdown. 厌恶排斥是一种意见问题-但是,如果有理由相信某个函数或方法将被多次调用或被快速调用,则异常将导致速度显着下降。 I learned this from my previous question , where I was previously relying on a thrown exception to return a default value rather than doing parameter checking to return that default. 我从上一个问题中学到了这一点,在该问题中 ,我以前依靠抛出的异常返回默认值,而不是通过参数检查返回默认值。

Of course, exceptions can still exist for any reason, and you shouldn't be afraid to use or throw one if necessary - especially ones that could potentially break the normal flow of the calling function. 当然,由于任何原因仍然可以存在异常,如果有必要,您不应该害怕使用或抛出异常-尤其是那些可能破坏调用函数正常流程的异常。

I disagree with the above comments that an exception is inefficient in this instance, especially since it's being used in an I/O bound operation. 我不同意上面的评论,在这种情况下,异常是低效的,尤其是因为它是在I / O绑定操作中使用的。

Here's a more realistic example using Django with an in-memory sqlite database. 这是将Django与内存中的sqlite数据库结合使用的更实际的示例。 Each of a 100 different queries was run, then averaged for each of a 100 runs. 每运行100个不同的查询,然后对每100个运行进行平均。 Although I doubt if it would matter, I also changed the order of execution. 尽管我怀疑这是否重要,但我也更改了执行顺序。

With ObjectDoesNotExist... 0.102783939838
Without exception ........ 0.105322141647

With ObjectDoesNotExist... 0.102762134075
Without exception ........ 0.101523952484

With ObjectDoesNotExist... 0.100004930496
Without exception ........ 0.107946784496

You can instrument this in your own Django environment, but I doubt if your time is well spent avoiding this exception. 您可以在自己的Django环境中对此进行检测,但是我怀疑您的时间是否花在了避免此异常上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM