hasattr()vs try-except块来处理不存在的属性

if hasattr(obj, 'attribute'): # do somthing 

VS

 try: # access obj.attribute except AttributeError, e: # deal with AttributeError 

哪个应该是首选的,为什么?

hasattr内部迅速地执行与try/except块相同的任务:这是一个非常具体的,优化的,单任务的工具,因此在适用时应该优先select通用的替代scheme。

任何说明性能差异的长椅?

时间是你的朋友

 $ python -mtimeit -s 'class C(object): a = 4 c = C()' 'hasattr(c, "nonexistent")' 1000000 loops, best of 3: 1.87 usec per loop $ python -mtimeit -s 'class C(object): a = 4 c = C()' 'hasattr(c, "a")' 1000000 loops, best of 3: 0.446 usec per loop $ python -mtimeit -s 'class C(object): a = 4 c = C()' 'try: ca except: pass' 1000000 loops, best of 3: 0.247 usec per loop $ python -mtimeit -s 'class C(object): a = 4 c = C()' 'try: c.nonexistent except: pass' 100000 loops, best of 3: 3.13 usec per loop $ |positive|negative hasattr| 0.446 | 1.87 try | 0.247 | 3.13 

我几乎总是使用hasattr :这是大多数情况下的正确select。

有问题的情况是,当一个类重写__getattr__hasattr捕获所有的exception,而不是像您期望的那样捕获AttributeError 。 换句话说,下面的代码将会打印b: False即使看到一个ValueErrorexception会更合适:

 class X(object): def __getattr__(self, attr): if attr == 'a': return 123 if attr == 'b': raise ValueError('important error from your database') raise AttributeError x = X() print 'a:', hasattr(x, 'a') print 'b:', hasattr(x, 'b') print 'c:', hasattr(x, 'c') 

重要的错误因此消失了。 Python 3.2 ( issue9666 )已经解决了这个问题, hasattr现在只捕获AttributeError

一个简单的解决方法是编写一个这样的实用程序function:

 _notset = object() def safehasattr(thing, attr): return getattr(thing, attr, _notset) is not _notset 

这让我们来处理一下情况,然后可以提出适当的例外。

我想说这取决于你的函数是否可以接受没有devise属性对象,例如,如果你有两个调用函数,一个提供一个对象的属性,另一个提供没有它的对象。

如果唯一的情况下,你会得到一个没有属性的对象是由于一些错误,我会build议使用exception机制,即使它可能会更慢,因为我相信这是一个更清洁的devise。

底线:我认为这是一个devise和可读性问题,而不是效率问题。

还有第三种,也是更好的select:

 attr = getattr(obj, 'attribute', None) if attr is not None: print attr 

优点:

  1. getattr不具有Martin Geiser指出的exception吞咽行为 – 在旧的Pythons中, hasattr甚至会吞下KeyboardInterrupt

  2. 你检查对象是否有属性的正常原因是你可以使用该属性,这自然会导致它。

  3. 该属性是自动读取的,并且可以从其他线程更改对象的安全。 (但是,如果这是一个主要问题,您可能需要考虑在访问对象之前locking对象)。

  4. 它比try/finally短,通常比hasattr短。

  5. except AttributeError其他的AttributeErrors都可以捕获到所期望的其他AttributeErrors ,这会导致混淆行为。

  6. 访问一个属性比访问一个局部variables慢(特别是如果它不是一个普通的实例属性)。 (虽然说实话,Python中的微观优化通常是愚蠢的事情。)

需要注意的一件事情是,如果你关心obj.attribute设置为None的情况,你需要使用一个不同的哨兵值。

如果这只是你正在testing的一个属性,我会说使用hasattr 。 但是,如果您要对可能存在或不存在的属性进行多次访问,则使用try块可能会为您节省一些键入空间。

从实际的angular度来看,在大多数语言中使用条件总是比处理exception要快得多。

如果你想要处理当前函数之外某个属性不存在的情况,那么exception是最好的方法。 您可能想要使用exception而不是条件的指示符是条件只是设置标志并中止当前操作,而其他地方的其他位置将检查该标志并基于该标志采取措施。

也就是说,正如Rax Olgud所指出的那样,与他人的沟通是代码的一个重要属性,而你所说的“这是一种特殊的情况”而不是“这是我希望发生的事情”可能更重要。

我build议选项2.如果其他线程正在添加或删除属性,选项1有一个竞争条件。

另外python有一个成语 ,EAFP(比容许更容易要求原谅)比LBYL(“看你跳跃”之前)好。

如果不具有该属性不是错误条件,则exception处理变体有一个问题:在访问obj.attribute时,也会捕获可能在内部发生的AttributeErrors(例如,因为属性是一个属性,因此访问它会调用一些代码)。

至less在程序到底发生了什么时,忽略了人的可读性等部分(实际上大部分时间比性能更重要(至less在这种情况下 – 具有这种性能),正如罗伊·阿德勒和其他人所指出的那样)。

尽pipe如此,从这个angular度来看,它然后成为一个select之间的问题

 try: getattr(obj, attr) except: ... 

 try: obj.attr except: ... 

因为hasattr只是使用第一种情况来确定结果。 食物的思想;-)

首先。

越短越好。 例外情况应该是例外。