how to detect whether a python variable is a callable?

またの名を「属性は呼び出し可能や否や」。

これはそのまんま、ではあって、built-in の callable を使うだけ。

z.py
 1 # -*- coding: utf-8 -*-
 2 a00 = 1
 3 a01 = [1]
 4 a02 = {"x": 1}
 5 a03 = range(10)
 6 a04 = map
 7 a05 = lambda x: x**2
 8 #
 9 class A06:
10     pass
11 a07 = A06()
12 #
13 class A08(object):
14     pass
15 a09 = A08()
16 #
17 class A10(object):
18     def __call__(self):
19         return ""
20 a11 = A10()
21 #
22 class A12(object):
23     pass
24 A12.__call__ = lambda self: ""
25 a13 = A12()
26 #
27 for attr in sorted(locals().keys(), key=lambda x: x.lower()):
28     import sys
29     v = getattr(sys.modules[__name__], attr)
30     # ==============================================================
31     print("%s: %s, %s, %r" % (attr, callable(v), type(v), v))
32     # ==============================================================
33 #
34 # ==============================================================
35 print("----- A14")
36 # ==============================================================
37 class A14(object):
38     __y = 1
39 
40     @property
41     def x(self):
42         return "zzz"
43     #
44     def gety(self):
45         return self.__y
46     def sety(self, value):
47         self.__y = value
48     def dely(self):
49         del self.__y
50     y = property(gety, sety, dely, "I'm the 'y' property.")
51     #
52 
53 for attr in filter(lambda a: not a.startswith("_"), dir(A14)):
54     v = getattr(A14, attr)
55     # ==============================================================
56     print("%s: %s, %s, %r" % (attr, callable(v), type(v), v))
57     # ==============================================================
58 
59 for attr in filter(lambda a: not a.startswith("_"), dir(A14())):
60     v = getattr(A14(), attr)
61     # ==============================================================
62     print("%s: %s, %s, %r" % (attr, callable(v), type(v), v))
63     # ==============================================================
64 #
 1 me@host: ~$ python z.py
 2 __builtins__: False, <type 'module'>, <module '__builtin__' (built-in)>
 3 __doc__: False, <type 'NoneType'>, None
 4 __file__: False, <type 'str'>, 'z.py'
 5 __name__: False, <type 'str'>, '__main__'
 6 __package__: False, <type 'NoneType'>, None
 7 a00: False, <type 'int'>, 1
 8 a01: False, <type 'list'>, [1]
 9 a02: False, <type 'dict'>, {'x': 1}
10 a03: False, <type 'list'>, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
11 a04: True, <type 'builtin_function_or_method'>, <built-in function map>
12 a05: True, <type 'function'>, <function <lambda> at 0x00000000025154A8>
13 A06: True, <type 'classobj'>, <class __main__.A06 at 0x00000000023DE2E8>
14 a07: False, <type 'instance'>, <__main__.A06 instance at 0x000000000251E108>
15 A08: True, <type 'type'>, <class '__main__.A08'>
16 a09: False, <class '__main__.A08'>, <__main__.A08 object at 0x00000000025164E0>
17 A10: True, <type 'type'>, <class '__main__.A10'>
18 a11: True, <class '__main__.A10'>, <__main__.A10 object at 0x0000000002516550>
19 A12: True, <type 'type'>, <class '__main__.A12'>
20 a13: True, <class '__main__.A12'>, <__main__.A12 object at 0x00000000025165C0>
21 ----- A14
22 dely: True, <type 'instancemethod'>, <unbound method A14.dely>
23 gety: True, <type 'instancemethod'>, <unbound method A14.gety>
24 sety: True, <type 'instancemethod'>, <unbound method A14.sety>
25 x: False, <type 'property'>, <property object at 0x00000000024F7F98>
26 y: False, <type 'property'>, <property object at 0x000000000251F048>
27 dely: True, <type 'instancemethod'>, <bound method A14.dely of <__main__.A14 object at 0x00000000025166D8>>
28 gety: True, <type 'instancemethod'>, <bound method A14.gety of <__main__.A14 object at 0x0000000002516710>>
29 sety: True, <type 'instancemethod'>, <bound method A14.sety of <__main__.A14 object at 0x00000000025166D8>>
30 x: False, <type 'str'>, 'zzz'
31 y: False, <type 'int'>, 1

びっくりするような結果はないよね? hasattr(obj, "__call__") も近いことは出来るけれど、how to detect whether a python variable is a function? – Stack Overflowには、ちょっとヘンな例も載ってたりする:

 1 # -*- coding: utf-8 -*-
 2 #
 3 class Xyz(object):
 4     def __call__(self):
 5         return "xyz"
 6 aaa = Xyz()
 7 print(callable(aaa))  # => True
 8 print(hasattr(aaa, "__call__"))  # => True
 9 print(aaa())  # => "xyz"
10 
11 del Xyz.__call__
12 aaa.__call__ = lambda self: "xxx"
13 #
14 print(callable(aaa))  # => False
15 print(hasattr(aaa, "__call__"))  # => True
16 aaa()  # cause TypeError: 'Xyz' object is not callable

あたりめーじゃねーか、としか言えないんだけれど、「hasattr(obj, "__call__")じゃダメな場合もあるぜ」と言いたいみたいね。