使用callable(x)vs。hasattr(x,“__ call__”)

时间:2013-05-05 19:03:24

标签: python python-3.x callable

我正在编写针对3.2及更高版本的Python。看起来使用内置函数callable是最简单有效的方法。我见过针对hasattr(x, "__call__")collections.Callable(x)的建议,并且只是在尝试通话时使用try/except

我测试了可调用的项目(类和函数),使用timeit进行100,000次迭代;在两种情况下,使用callable只需要检查属性的大约75%的时间。当项目不可调用(整数和字符串)时,使用与类或函数相同的可调用停留时,检查属性的价格比类或函数贵2.3倍。我没想到会有这种差异,但它也支持简洁明了的callable(x)方法。

但是我对Python比较新,没有专家,所以有没有我不知道应该使用hasattr方法或其他方法的原因?

FWIW,各种时间的结果如下。第一个字符只是t表示timeit,第二个字符表示被测对象的类型(c = class,f = function,i = integer,s = string),其余表示方法(attr-check属性, call - use callable,try - use try / except)。

tcattr 0.03665385400199739
tccall 0.026238360142997408
tctry 0.09736267629614304
tfattr 0.03624538065832894
tfcall 0.026362861895904643
tftry 0.032501874250556284
tiattr 0.08297350149314298
ticall 0.025826044152381655
titry 0.10657657453430147
tsattr 0.0840187013927789
tscall 0.02585409547373274
tstry 0.10742772077628615

3 个答案:

答案 0 :(得分:6)

hasattr()会返回比callable更多的误报:

>>> class X(object):
...     def __getattr__(self, name):
...         return name
...
>>> i = X()
>>> from collections import Callable
>>> isinstance(i, Callable)
False
>>> callable(i)
False
>>> hasattr(i, '__call__')
True
>>> i()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'X' object is not callable

我不确定您正在测试哪个callable,但两者看起来都比hasattr更好并处理更多案例,所以我会用它们代替hasattr()

答案 1 :(得分:4)

callable不仅是最快的,而且Zen提供了四个更重要的理由来使用它而不是其他两个装置:

  

美丽胜过丑陋   明确比隐含更好   简单比复杂更好   可读性很重要。

答案 2 :(得分:4)

好问题!我会说你应该使用callable。除速度问题外还有几点:

  1. 它明确,简单,清晰,简洁,整洁。
  2. 这是一个内置的Python,所以任何不知道它的功能的人都可以轻松找到。
  3. try... except TypeError有一个问题:TypeError有时会被其他内容引发。例如,如果您成功调用了一个在其正文中引发TypeError的函数,except将错误地捕获该函数并假设该对象不可调用。
  4. 一些常见的自定义操作(例如__getattr__)可能会导致hasattr出错。
  5. collections.abc.Callable对于如此简单的事情来说似乎是一个相当沉重的机器。毕竟,callable做同样的工作。
  6. 脚注:try块在Python中是very common pattern用于此类事情,因此您可能会在其他人的代码中看到很多块。但是,正如我上面所概述的那样,这是一个不太适合的情况。