【问题标题】:python isinstance vs hasattr vs try/except: What is better?python isinstance vs hasattr vs try/except:什么更好?
【发布时间】:2014-01-28 06:44:24
【问题描述】:

我试图找出不同方法之间的权衡,以确定是否使用对象obj 可以执行操作do_stuff()。据我了解,有三种方法可以确定这是否可行:

# Way 1
if isinstance(obj, Foo):
    obj.do_stuff()

# Way 2
if hasattr(obj, 'do_stuff'):
    obj.do_stuff()

# Way 3
try:
    obj.do_stuff()
except:
    print 'Do something else'

首选方法是什么(为什么)?

【问题讨论】:

  • 每件事都有时间。通常尝试/除外(或者甚至不except,只是让异常渗透到调用堆栈中)是要走的路,但是每个规则都有例外(hohoho)。例如,字符串和列表共享许多方法,但您通常希望在递归调用中对它们做不同的事情。

标签: python exception-handling attributes isinstance


【解决方案1】:

我相信 Python 编码人员通常更喜欢最后一种方法,因为在 Python 社区中教授 motto:“请求宽恕比请求许可更容易”(EAFP)。

简而言之,座右铭的意思是避免在做某事之前检查您是否可以做某事。相反,只需运行该操作。如果失败,请适当处理。

另外,第三种方法还有一个额外的好处,就是明确操作应该起作用。


话虽如此,您确实应该避免像这样使用裸露的except。这样做将捕获任何/所有异常,甚至是不相关的异常。相反,最好专门捕获异常。

在这里,您将要捕获AttributeError:

try:
    obj.do_stuff()   # Try to invoke do_stuff
except AttributeError:
    print 'Do something else'  # If unsuccessful, do something else

【讨论】:

  • 尝试访问方法属性,然后在else 子句中调用它,而不是简单地尝试在try 子句中调用它有什么好处? (我想您可能想要区分在 do_stuff 内部产生的 AttributeError 和由 do_stuff 生成的不存在的。)
  • @chepner - 不,很好。我在想别的事。
【解决方案2】:

使用isinstance 检查与使用duck typing 的Python 约定背道而驰。

hasattr 工作正常,但它是 Look Before you Leap 而不是更 Pythonic 的 EAFP。

您对方式 3 的实现是危险的,因为它会捕获所有错误,包括由 do_stuff 方法引发的错误。你可以选择更精确的:

try:
    _ds = obj.do_stuff
except AttributeError:
    print('Do something else')
else:
    _ds()

但在这种情况下,尽管开销很小,我还是更喜欢方式 2 - 它更具可读性。

【讨论】:

  • 我怀疑,您的意思是“hasattr 工作正常,但它是 EAFP 而不是更 Pythonic 的 LBYL。”以另一种方式阅读“hasattr 工作正常,但它是 LBYL 而不是更 Pythonic 的 EAFP”。
  • @mloskot 谢谢,已修复。
【解决方案3】:

正确答案是“都不是” hasattr 提供了功能,但它可能是所有选项中最糟糕的。

我们使用 Python 的面向对象特性,因为它可以工作。 OO 分析永远不会准确并且经常令人困惑,但是我们使用类层次结构,因为我们知道它们可以帮助人们更快地更好地工作。人们掌握对象,一个好的对象模型可以帮助编码人员更快地改变事物并且减少错误。正确的代码最终聚集在正确的位置。对象:

  • 可以直接使用而不考虑存在哪个实现
  • 明确需要更改的内容和位置
  • 隔离对某些功能的更改与对某些其他功能的更改 - 您可以修复 X ​​而不必担心会破坏 Y

hasattr 与 isinstance

必须使用 isinstance 或 hasattr 表明对象模型已损坏或我们使用不正确。正确的做法是修复对象模型或改变我们使用它的方式。 这两个结构具有相同的效果,并且在命令式“我需要代码来执行此操作”的意义上它们是等价的。结构上有很大的不同。在第一次遇到这种方法时(或者在做了几个月的其他事情之后),isinstance 传达了更多关于实际发生的事情和其他可能的信息。 Hasattr 不会“告诉”你任何事情。

长期的开发历史使我们远离了 FORTRAN 和带有大量“我是谁”开关的代码。我们选择使用对象是因为我们知道它们有助于使代码更易于使用。通过选择 hasattr,我们提供了功能,但没有任何东西是固定的,代码比我们开始之前更糟糕。将来添加或更改此功能时,我们将不得不处理分组不均且至少具有两个组织原则的代码,其中一些在“应该”的地方,其余的则随机分散在其他地方。没有什么可以使它连贯一致。这不是一个错误,而是散布在通过您的 hasattr 的任何执行路径上的潜在错误雷区。

所以如果有选择的话,顺序是:

  1. 使用对象模型或修复它或至少找出问题所在 使用它以及如何修复它
  2. 使用 isinstance
  3. 不要使用 hasattr

【讨论】:

  • 在这种情况下,“修复对象模型”是什么意思?另外,这里的“isinstance”有什么用?例如,您可能想检查“object”是否是具有 shape 属性的数据结构,这将是一个问题,必须先列出所有结构以传递给“isinstance”。最后您如何看待被某些人认为是好的解决方案的“getattr”和“try/except”?
猜你喜欢
  • 2011-04-25
  • 2016-08-30
  • 1970-01-01
  • 2017-07-27
  • 2015-05-22
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多