我正在使用Python,并且每当必须验证函数输入时,我都认为输入有效,然后捕获了错误。

就我而言,我有一个通用的Vector()类,用于一些不同的事情,其中​​之一是加法。它既充当Color()类又充当Vector(),因此,当我在Color()中添加标量时,应将该常数添加到每个单独的组件中。 Vector()Vector()添加需要按组件进行添加。

这段代码被用于光线追踪器,因此任何速度提升都很棒。

这是我的Vector()类的简化版本:

class Vector:
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z

  def __add__(self, other):
    try:
      return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
    except AttributeError:
      return Vector(self.x + other, self.y + other, self.z + other)

我目前正在使用try...except方法。有人知道更快的方法吗?

编辑:由于有了答案,我尝试并测试了以下解决方案,该解决方案在添加Vector()对象之前专门检查了类名:
class Vector:
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z

  def __add__(self, other):
    if type(self) == type(other):
      return Vector(self.x + other.x, self.y + other.y, self.z + other.z)
    else:
      return Vector(self.x + other, self.y + other, self.z + other)

我使用 timeit 对这两个代码块进行了速度测试,结果非常重要:
 1.0528049469 usec/pass for Try...Except
 0.732456922531 usec/pass for If...Else
 Ratio (first / second): 1.43736090753

我还没有测试过Vector()类,而没有任何输入验证(即,将检查从类中移出并移到实际代码中),但我想它比if...else方法还要快。

较晚更新:回顾此代码,这不是最佳解决方案。

OOP可以使速度更快:
class Vector:
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z

  def __add__(self, other):
    return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

class Color(Vector):
  def __add__(self, other):
    if type(self) == type(other):
      return Color(self.x + other.x, self.y + other.y, self.z + other.z)
    else:
      return Color(self.x + other, self.y + other, self.z + other)

最佳答案

我赞成马特·乔纳(Matt Joiner)的回答,但想补充一些观察意见,以使我们清楚地了解,与其他一些因素一起,在预检查条件之间进行选择时, 4 倍很重要(称为LBYL或“先看后看”)您跃跃欲试”),只处理异常(称为EAFP或“比许可权更容易获得宽恕”)。

这些时间是:

  • 使用LBYL进行成功检查的时间
  • 使用LBYL时检查失败的时间
  • EAFP不引发异常的时间
  • 用EAFP引发异常的时间

  • 其他因素是:
  • 检查成功/失败或抛出异常/未抛出异常的典型比率
  • 是否存在阻止使用LBYL的比赛条件

  • 最后一点是首先需要解决的问题:如果存在争用条件的可能性,那么您别无选择,必须使用异常处理。一个典型的例子是:
    if <dir does not exist>:
        <create dir> # May still fail if another process creates the target dir
    

    由于LBYL并不排除此类情况的异常(exception),因此它没有真正的好处,也没有做出判断的要求:EAFP是唯一可以正确处理比赛条件的方法。

    但是,如果没有竞争条件,则两种方法都可能可行。它们提供了不同的权衡:
  • 如果没有引发异常,则EAFP接近免费的
  • 但是,如果发生异常,则相对昂贵,因为展开堆栈,创建异常并将其与异常处理子句
  • 进行比较涉及大量处理
    相比之下,
  • LBYL可能会带来较高的固定成本:无论是否成功
  • 总是执行附加检查

    然后得出以下决策标准:
  • 是否已知这段代码对应用程序的速度至关重要?如果不是,那么不必担心两者中的哪一个更快,而不必担心两者中的哪一个更容易阅读。
  • 预检查是否比引发和捕获异常的成本贵?如果是,则EAFP总是更快,应该使用。
  • 如果答案为“否”,事情将会变得更加有趣。在那种情况下,更快的速度取决于成功或错误情况是否更常见,以及预检查和异常处理的相对速度。明确地回答这个问题需要实际的时序测量。

  • 作为一个粗略的经验法则:
  • 如果存在潜在的种族状况,请使用EAFP
  • 如果速度不是很关键,请使用您认为更容易阅读的
  • 如果预检查很昂贵,请使用EAFP
  • 如果您希望操作在大多数时间都能成功*,请使用EAFP
  • 如果您期望操作失败超过一半的时间,请使用LBYL
  • 如果有疑问,请测量

  • *在这种情况下,人们对于“大多数时间”的看法会有所不同。对我来说,如果我希望该操作能成功完成一半以上的时间,那我当然会使用EAFP,直到我有理由怀疑这段代码是实际的性能瓶颈。

    10-04 20:29