python isinstance vs hasattr vs try/except:什么更好?

Fel*_*lix 14 python attributes exception-handling isinstance

我试图找出确定是否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'
Run Code Online (Sandbox Code Playgroud)

哪种方法首选(以及为什么)?

iCo*_*dez 10

我相信Python编码器通常首选最后一种方法,因为Python社区教授的座右铭是:"更容易请求宽恕而非许可"(EAFP).

简而言之,座右铭意味着避免在你做之前检查你是否可以做某事.相反,只需运行该操作.如果失败,请妥善处理.

而且,第三种方法具有额外的优点,即清楚地表明操作应该起作用.


话虽如此,你真的应该避免使用这样的裸露except.这样做会捕获任何/所有异常,甚至是不相关的异常.相反,最好特别捕获异常.

在这里,您需要捕获AttributeError:

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


phi*_*hag 6

检查isinstance运行与使用duck typing的Python约定相反.

hasattr工作正常,但是在你跳跃之前,而不是更多的Pythonic EAFP.

您对方式3的实现很危险,因为它可以捕获任何和所有错误,包括由do_stuff方法引发的错误.你可以更精确地去:

try:
    _ds = obj.do_stuff
except AttributeError:
    print('Do something else')
else:
    _ds()
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,我更喜欢方式2,尽管有轻微的开销 - 它更具可读性.


小智 5

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

\n\n

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

\n\n
    \n
  • 可以直接使用而不考虑存在哪个实现
  • \n
  • 明确需要改变什么以及哪里
  • \n
  • 将某些功能的更改与其他功能的更改隔离 \xe2\x80\x93 您可以修复 X ​​而不必担心会破坏 Y
  • \n
\n\n

hasattr 与 isinstance

\n\n

必须使用 isinstance 或 hasattr 表明对象模型已损坏或我们使用不正确。正确的做法是修复对象模型或改变我们使用它的方式。\n这两个构造具有相同的效果,并且在命令式 \xe2\x80\x98 中我需要代码来执行此操作\xe2\x80\x99 感觉它们是等效的。结构上存在巨大差异。第一次遇到此方法时(或在做了其他事情几个月后), isinstance 传达了有关实际发生的情况以及其他可能发生的情况的更多信息。Hasattr 不会告诉你任何东西。

\n\n

悠久的发展历史使我们远离了 FORTRAN 和带有大量 \xe2\x80\x98who am I\xe2\x80\x99 开关的代码。我们选择使用对象是因为我们知道它们有助于使代码更易于使用。通过选择 hasattr,我们提供了功能,但是没有修复任何内容,代码比我们开始之前更加破碎。将来添加或更改此功能时,我们将不得不处理不均匀分组且至少有两个组织原则的代码,其中一些是 \xe2\x80\x98 应该是 \xe2\x80\x99 的位置,其余的则在 \xe2\x80\x98 的位置随机分散在其他地方。没有什么可以使它连贯。这不是一个错误,而是一个潜在错误的雷区,分散在经过您的 hasattr 的任何执行路径上。

\n\n

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

\n\n
    \n
  1. 使用对象模型或修复它,或者至少找出它的问题\n以及如何修复它
  2. \n
  3. 使用 isinstance
  4. \n
  5. 不要\xe2\x80\x99t 使用 hasattr
  6. \n
\n