python isinstance vs hasattr vs try/except: What is better?
我试图找出不同方法之间的权衡,以确定对象
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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' |
哪个是首选方法(为什么)?
我相信最后一种方法通常被Python编码人员首选,因为在Python社区中有一句格言:"请求宽恕比请求许可更容易"(EAFP)。
简而言之,这句格言的意思是避免在做之前检查你是否能做些什么。相反,只需运行该操作。如果失败,请妥善处理。
另外,第三种方法还有一个额外的优点,就是可以清楚地表明操作应该有效。
有了这一点,您真的应该避免使用这样的裸
在这里,您将要捕获一个
1 2 3 4 | try: obj.do_stuff() # Try to invoke do_stuff except AttributeError: print 'Do something else' # If unsuccessful, do something else |
使用
方法3的实现是危险的,因为它捕获任何和所有错误,包括由
1 2 3 4 5 6 | try: _ds = obj.do_stuff except AttributeError: print('Do something else') else: _ds() |
但在本例中,尽管开销很小,但我还是更喜欢第2种方式——它的可读性更高。
正确答案是"两者都不是"hasattr提供了功能,但它可能是所有选项中最糟糕的。
我们使用Python的面向对象特性,因为它可以工作。OO分析永远不会准确,而且经常混淆,但是我们使用类层次结构,因为我们知道它们可以帮助人们更快地完成更好的工作。人们掌握对象,一个好的对象模型可以帮助编码人员更快地改变事情,减少错误。正确的代码最终聚集在正确的位置。对象:
- 可以在不考虑存在哪种实现的情况下使用
- 明确需要改变的地方
- 将某些功能的更改与某些其他功能的更改隔离开来–您可以修复X,而不必担心会破坏Y
hasattr与isinstance
必须使用isInstance或hasattr表示对象模型已损坏或使用错误。正确的做法是修复对象模型或更改我们使用它的方式。这两个构造具有相同的效果,在命令式"我需要代码来做这件事"中,它们是等效的。结构上有很大的不同。在第一次使用这种方法时(或者在做了几个月的其他事情之后),IsInstance会传递更多关于实际发生的事情以及其他可能发生的事情的信息。哈萨特不会"告诉"你任何事情。
长期的开发历史使我们远离了Fortran,而是使用了大量的"我是谁"开关来编写代码。我们选择使用对象是因为我们知道它们有助于使代码更容易使用。通过选择hasattr,我们提供了功能,但是没有什么可以修复,代码比我们开始之前更容易被破坏。在将来添加或更改此功能时,我们将不得不处理不平等分组且至少有两个组织原则的代码,其中一些原则是"应该"的,其余的则随机分散在其他地方。没有什么可以使它连贯。这不是一个bug,而是散布在通过hasattr的任何执行路径上的潜在错误的雷区。
因此,如果有选择的话,顺序是: