classification
Title: replace hasattr(obj, '__call__') with callable(obj)
Type: performance Stage: resolved
Components: Library (Lib) Versions: Python 3.2, Python 3.3
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: eric.araujo, flox, haypo, jcea, pitrou, python-dev
Priority: normal Keywords: patch

Created on 2011-10-24 19:46 by flox, last changed 2011-10-28 12:53 by python-dev. This issue is now closed.

Files
File name Uploaded Description Edit
issue13258_callable.diff flox, 2011-10-24 19:48 review
issue13258_callable_v2.diff flox, 2011-10-24 20:16 review
Messages (10)
msg146320 - (view) Author: Florent Xicluna (flox) * (Python committer) Date: 2011-10-24 19:46
Now that callable() is back in 3.2, we may replace hasattr(obj, '__call__') with callable(obj).

The built-in function is easier to read and gives better performance than attribute lookup.


$ ./python -m timeit "hasattr(None, '__call__')"
100000 loops, best of 3: 4.09 usec per loop
$ ./python -m timeit "hasattr(str, '__call__')"
1000000 loops, best of 3: 1.3 usec per loop

$ ./python -m timeit "callable(None)"
1000000 loops, best of 3: 0.299 usec per loop
$ ./python -m timeit "callable(str)"
1000000 loops, best of 3: 0.369 usec per loop
msg146321 - (view) Author: Florent Xicluna (flox) * (Python committer) Date: 2011-10-24 19:48
Proposed patch.
msg146323 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-10-24 20:07
For packaging I'm not sure it's worth complicating backporting.
msg146324 - (view) Author: Florent Xicluna (flox) * (Python committer) Date: 2011-10-24 20:16
Updated with a special note for "packaging".
msg146326 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2011-10-24 21:44
callable() is not just faster, it's also "more correct": hasattr(obj, "__call__") doesn't call base classes. See callable() of the six module:


def callable(obj):
  return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
msg146328 - (view) Author: Florent Xicluna (flox) * (Python committer) Date: 2011-10-24 22:18
We have so many alternatives, it's funny ...


def callable(obj):
    return hasattr(obj, '__call__') or hasattr(obj, '__bases__')

def callable(obj):
    return isinstance(obj, collections.abc.Callable)

def callable(obj):
    return hasattr(obj, '__call__') or type(obj) == types.ClassType

def callable(obj):
    return any("__call__" in klass.__dict__
               for klass in type(obj).__mro__)
msg146330 - (view) Author: Jesús Cea Avión (jcea) * (Python committer) Date: 2011-10-24 22:23
Is it actually appropiate to commit this to 3.2?. I am neutral to it, just asking.
msg146331 - (view) Author: STINNER Victor (haypo) * (Python committer) Date: 2011-10-24 22:25
> Is it actually appropiate to commit this to 3.2?

If it fixes a bug, the fix should be backported to 3.2.
msg146371 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-10-25 15:05
This change is fine for packaging.  In the 2.x backport I already use callable (and damn the py3k warning) and  the 3.x backport uses the incorrect hasattr(inst, '__call__'); I’ll change that to use a backported d2.compat.callable.
msg146557 - (view) Author: Roundup Robot (python-dev) Date: 2011-10-28 12:53
New changeset 8e57b5d8f58f by Florent Xicluna in branch '3.2':
Closes #13258: Use callable() built-in in the standard library.
http://hg.python.org/cpython/rev/8e57b5d8f58f
History
Date User Action Args
2011-10-28 12:53:41python-devsetstatus: open -> closed

nosy: + python-dev
messages: + msg146557

resolution: fixed
stage: patch review -> resolved
2011-10-25 15:05:40eric.araujosetmessages: + msg146371
2011-10-24 22:25:56hayposetmessages: + msg146331
2011-10-24 22:23:53jceasetnosy: + jcea
messages: + msg146330
2011-10-24 22:18:38floxsetmessages: + msg146328
stage: patch review
2011-10-24 21:44:57hayposetnosy: + haypo
messages: + msg146326
2011-10-24 20:16:12floxsetfiles: + issue13258_callable_v2.diff

messages: + msg146324
2011-10-24 20:07:55pitrousetnosy: + eric.araujo, pitrou
messages: + msg146323
2011-10-24 19:48:20floxsetfiles: + issue13258_callable.diff
keywords: + patch
messages: + msg146321
2011-10-24 19:46:14floxcreate