Using called (x) vs. hasattr (x, "__call__")

I am writing Python that targets version 3.2 and higher. It seems that using the built-in function called is the easiest and most efficient way to do this. I saw recommendations for hasattr(x, "__call__") , collections.Callable(x) and just used try/except around the call attempt.

I tested the elements called (class and function) using timeit with 100,000 iterations; in both cases, using the called object takes only about 75% of the attribute verification time. When an element cannot be called (an integer and a string) using called residuals with the same cost as a class or function, when checking an attribute is approximately 2.3 times more expensive than for a class or function. I did not expect this difference, but it also contributes to the clear and concise callable(x) approaches.

But I'm relatively new to Python and not an expert, so are there reasons why I don't know if I should use the hasattr approach or another approach?

FWIW, the results of various time periods follow. The first character is just t for timeit, the second is the type of object being tested (c = class, f = function, i = integer, s = string), and the rest is indicated by the method (attr - check attribute, 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
+7
source share
3 answers

hasattr() will return more false positives than 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 

I'm not sure which callable you tested, but both look better than hasattr and handle more cases, so I would use them instead of hasattr() .

+6
source

callable is not only the fastest, but Zen provides four more important reasons to use it instead of two other devices:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Readability indicators.

+4
source

Great question! I would say that you should use callable . A few questions besides speed:

  • It is explicit, simple, understandable, short and neat.
  • It is built-in Python, so anyone who does not yet know what it is doing can easily find it.
  • try... except TypeError has a problem: TypeError can sometimes be raised by other things. For example, if you successfully call a function that raises a TypeError in your body, except will mistakenly catch this and assume that the object was not called.
  • Some common settings, such as __getattr__ , can cause hasattr errors.
  • collections.abc.Callable seems like a pretty heavy machine for something so simple. In the end, callable does the same job.

Footnote: The try block is a very common pattern in Python for this kind of thing, so you can see it a lot in other people's code. However, as I stated above, this is one case when it does not quite fit.

+4
source

All Articles