2013-07-18 34 views
3

例如:dir()中hasattr()和'attribute'有什么区别?

>>> s = 'string' 
>>> hasattr(s, 'join') 
True 
>>> 'join' in dir(s) 
True 

Python documentationhasattr实现调用getattr,看它是否引发异常或没有。但是,这会导致很大的开销,因为所获得的值将被丢弃,并且可能会引发异常。

问题是如果调用'attribute' in dir(obj)意味着同样的事情,它是更快,更安全还是可能会在特定场合失败?

回答

8

这是不太一样的东西。 dir()省略属性,getattr()hasattr()会找到的诊断工具。

dir() documentation

默认dir()机制不同类型的对象的不同表现,因为它试图产生最相关的,而不是完整的,信息:

  • 如果该对象是一个模块对象,该列表包含模块属性的名称。
  • 如果对象是一个类型或类对象,则该列表包含其属性的名称,并递归地显示其基础的属性。
  • 否则,该列表包含对象的属性名称,其类属性的名称以及其类的基类的属性的递归。

注意:由于dir()提供主要是使用的便利性,在一个交互式提示,它试图比它试图提供一个有趣的 集名称更多的提供严格或一致的定义的一组名称,其详细行为可能会在 版本中发生变化。例如,当参数是一个类时,metaclass属性不在结果 列表中。

强调我的。

这意味着hasattr()会发现元类提供属性,但dir()不会,什么是发现可以不同翻过的Python版本作为函数的定义是提供调试方便,不完备性。

演示具体的元类场景,其中hasattr()发现元类定义的属性:

>>> class Meta(type): 
...  foo = 'bar' 
... 
>>> class Foo(metaclass=Meta): 
...  pass 
... 
>>> hasattr(Foo, 'foo') 
True 
>>> 'foo' in dir(Foo) 
False 

最后但并非最不重要的:

如果对象有一个名为__dir__()方法,此方法将被调用并且必须返回属性列表。

这意味着hasattr()dir()可以更广泛地中“发现”如果.__dir__()法已经实施了什么属性上有所差异。

只要坚持hasattr()。首先,它的速度更快,因为对属性的测试很便宜,因为这只是对一个或多个字典的成员测试。枚举所有字典密钥并在实例,类和基类之间进行合并会导致CPU成本高得多。

+0

使用'hasattr'的一个缺点是它会触发属性执行,这可能是高成本的。在诸如Django'OneToOneField'关系的情况下,这甚至会触发数据库查询。我不认为有其他选择,是吗? –

+0

@AugustoMen:您可以使用*特定于应用程序*的测试方法来查看存在的属性。例如,我确定Django有枚举字段的方法。 –

4

的hasattr快100倍以上:)

In [137]: s ='string' 

In [138]: %timeit hasattr(s, 'join') 
10000000 loops, best of 3: 157 ns per loop 

In [139]: %timeit 'join' in dir(s) 
100000 loops, best of 3: 19.3 us per loop 
1

dir()不叫getattr(),或类似的东西,这取决于类“描述”本身:

>>> class Foo(object): 
...  def __dir__(self): 
...   return ['apples', 'bananas', 'mangoes'] 
...  def __getattr__(self, attr): 
...   return {'a': 1}[attr] 
...  
>>> foo = Foo() 
>>> hasattr(foo, 'a') 
True 
>>> hasattr(foo, 'apples') 
False 
>>> 'a' in dir(foo) 
False 
>>> 'apples' in dir(foo) 
True 

寻找文件时,您应该只使用dir()

0

hasattr()基本上是

try: 
    s.attribute 
    return True 
except AttributeError: 
    return False 

而 “的dir(多个)属性” 更像:

for attr in dir(s): 
    if attribute == attr: 
     return True 
return False 

因此,hasattr预计是快一点。

无论如何,如果我被允许走偏离轨道,那么我会建议这一点。 如果你想要做的事,如:

if hasattr(s, 'attributeName'): 
    s.attributeName() 
else: 
    do_stuff() 

那么它最好做这样的:

try: 
    s.attributeName() 
except AttributeError: 
    do_stuff() 

为什么?

  1. 为了避免额外的try-except块/ for循环的开销。
  2. 在Python中,请求宽恕比权限更容易。