我正在编写针对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
答案 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
。除速度问题外还有几点:
try... except TypeError
有一个问题:TypeError
有时会被其他内容引发。例如,如果您成功调用了一个在其正文中引发TypeError
的函数,except
将错误地捕获该函数并假设该对象不可调用。__getattr__
)可能会导致hasattr
出错。collections.abc.Callable
对于如此简单的事情来说似乎是一个相当沉重的机器。毕竟,callable
做同样的工作。脚注:try
块在Python中是very common pattern用于此类事情,因此您可能会在其他人的代码中看到很多块。但是,正如我上面所概述的那样,这是一个不太适合的情况。