例如:
>>> s = 'string'
>>> hasattr(s, 'join')
True
>>> 'join' in dir(s)
True
Python 文档说这hasattr
是实现调用getattr
并查看它是否引发异常。但是,这会导致很大的开销,因为获得的值会被丢弃并且可能会引发异常。
问题是调用是否'attribute' in dir(obj)
意味着同样的事情,是更快、更安全,还是在特定场合会失败?
这不完全一样。dir()
是一种诊断工具,它忽略了getattr()
那些会hasattr()
找到的属性。
从dir()
文档中:
默认
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 成本。
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
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()
在查找文档时使用。
hasattr() 基本上是
try:
s.attribute
return True
except AttributeError:
return False
而“目录中的属性”更像是:
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()
为什么?