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

python 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'

我试图找出不同方法之间的权衡,以确定是否可以使用object
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()