またの名を「属性は呼び出し可能や否や」。
これはそのまんま、ではあって、built-in の callable を使うだけ。
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__")
じゃダメな場合もあるぜ」と言いたいみたいね。