python isinstance vs hasattr vs try/Exception:什么更好?
我试图找出不同方法之间的权衡,以确定是否可以使用objectpython isinstance vs hasattr vs try/Exception:什么更好?,python,exception-handling,attributes,isinstance,Python,Exception Handling,Attributes,Isinstance,我试图找出不同方法之间的权衡,以确定是否可以使用objectobj执行操作do\u 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'
obj
执行操作do\u 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'
哪种方法是首选方法(以及为什么)?我认为Python程序员通常更喜欢最后一种方法,因为Python社区有一个教训:“请求原谅比允许更容易”(EAFP) 简而言之,这句格言的意思是避免在你做某事之前检查你是否能做某事。相反,只需运行该操作。如果失败,请妥善处理 此外,第三种方法还有一个额外的优点,即明确说明操作应该有效
话虽如此,你真的应该避免使用裸露的
,除了那样的。这样做将捕获任何/所有异常,甚至是不相关的异常。相反,最好是专门捕获异常
在这里,您需要捕获以下内容:
使用isinstance
进行检查与Python使用的惯例背道而驰
hasattr
工作正常,但它不是更像python
方法3的实现是危险的,因为它捕获任何和所有错误,包括由do\u stuff
方法引起的错误。您可以使用更精确的:
try:
_ds = obj.do_stuff
except AttributeError:
print('Do something else')
else:
_ds()
但是在这种情况下,我更喜欢方法2,尽管它的开销很小,只是可读性更好。正确的答案是“两者都不是”
hasattr提供了功能,但它可能是所有选项中最差的
我们使用python的面向对象特性,因为它可以工作。OO分析从来都不准确,而且经常混淆,但是我们使用类层次结构,因为我们知道它们可以帮助人们更快地完成更好的工作。人们掌握对象,一个好的对象模型可以帮助编码人员更快、更少地更改内容。正确的代码最终聚集在正确的位置。对象:
- 可以在不考虑存在哪个实现的情况下使用
- 明确需要更改的内容和位置
- 将对某些功能的更改与对其他功能的更改隔离开来–您可以修复X,而不用担心会破坏Y
hasattr vs isinstance
必须使用isinstance或hasattr表示对象模型已损坏或使用不正确。正确的做法是修复对象模型或更改我们使用它的方式。
这两个结构具有相同的效果,在命令式“我需要代码来完成这项工作”中,它们是等效的。在结构上存在着巨大的差异。在第一次使用这种方法时(或在做了几个月的其他事情之后),iInstance传递了大量有关实际情况和其他可能情况的信息。Hasattr不会“告诉”你任何事情
漫长的开发历史使我们远离了FORTRAN和带有大量“我是谁”开关的代码。我们选择使用对象是因为我们知道它们有助于使代码更易于使用。通过选择hasattr,我们提供了功能,但是没有任何东西是固定的,代码比我们开始之前更容易被破坏。在将来添加或更改此功能时,我们将不得不处理不平等分组的代码,这些代码至少有两个组织原则,其中一些是“应该”的,其余的则随机分散在其他地方。没有什么能使它更连贯。这不是一个bug,而是散布在通过hasattr的任何执行路径上的潜在错误雷区
因此,如果有任何选择,顺序是:
使用或修复对象模型,或者至少找出问题所在
使用它以及如何修复它
使用iInstance
不要使用hasattr
每件事都有时间。通常,try/except(或者甚至不except
,让异常渗透到调用堆栈中)是一种方法,但每个规则都有异常(hohoho)。例如,字符串和列表共享许多方法,但您通常希望在递归调用中使用它们执行不同的操作。尝试访问method属性,然后在else
子句中调用它,而不是简单地在try
子句中调用它,有什么好处吗?(我想你可能想区分在do_stuff
中提出的AttributeError
和由do_stuff
生成的do_stuff
不存在的错误。)@chepner-不,很好。我在想另外一件事。我想,你的意思是“hasattr工作正常,但EAFP代替了更具Python风格的LBYL。”换个角度看,“hasattr工作正常,但LBYL代替了更具Python风格的EAFP”。@mloskot谢谢,修复了。在这种情况下,“修复对象模型”是什么意思?还有,这里的“isinstance”有什么好处?例如,您可能需要检查“object”是否是一个具有shape属性的数据结构,这将是一个问题,必须先列出所有要传递给“isinstance”的结构。最后,您对一些人认为好的解决方案“getattr”和“try/except”有何看法?
try:
_ds = obj.do_stuff
except AttributeError:
print('Do something else')
else:
_ds()