В Python утиная типизация поэтому лично мне иногда очень хочется посмотреть, какие методы поддерживаются разными объектами. Был написан такой скрипт:
#!/usr/bin/python2
# coding: utf-8
import sys
import os
import getopt
def ins_to_line(st, ins, pos):
return st[:pos] + ins + st[pos + len(ins):]
def desc(tts, filter_f, pr_desc):
q = {}
for tt in tts:
t = getattr(__builtins__, tt)
for n in dir(t):
if n in q:
q[n].append(tt)
else:
q[n] = [tt]
f = dict(filter(lambda x: filter_f(len(x[1])), q.items()))
s = max(map(lambda x: len(x[0]), f.items()))
ins = {}
for i in tts:
s += 2
ins[i] = s
s += len(i)
ss = '. ' * (int(s/2)+1)
b_line = ss[1:s+1], ss[0:s]
pp = 0
for n, a in sorted(f.items(), key=lambda x: x[0]):
pp = 1 - pp
if pr_desc:
print('=' * 59)
t = ins_to_line(b_line[pp], n, 0)
for i in a:
t = ins_to_line(t, i, ins[i])
print(t)
if pr_desc:
print('_ ' * 30)
print(getattr(getattr(__builtins__, a[0]), n).__doc__)
def usage():
print((
'Usage:\n'
' {0} -[hd1nN] type_name_1 type_name_2 ...\n'
'Options:\n'
' Filters:\n'
' -1 print methods that present only in one cless\n'
' -n methods presented in not all clases\n'
' -N methods presented in all classes\n'
' -A all methods (default)\n'
' Detallisations:\n'
' -d print x.__doc__\n'
' -h this message and exit\n'
'Example:\n'
' {0} -1 int bool'
).format(os.path.basename(sys.argv[0])))
def main():
optlist, args = getopt.getopt(sys.argv[1:], 'hd1nN')
args_l = len(args)
if args_l == 0:
usage()
return
number = lambda x: True # All
print_description = False
for k, v in optlist:
if k == '-1':
number = lambda x: x == 1
elif k == '-n':
number = lambda x: x < args_l
elif k == '-N':
number = lambda x: x == args_l
elif k == '-A':
pass
elif k == '-d':
print_description = True
elif k == '-h':
usage()
return
else:
raise Exception('How?!')
desc(args, number, print_description)
if __name__ == '__main__':
main()
Код работает на обоих версиях: 2.x и 3.x.
Примеры использования:
Вывести методы, которые присутствую только в одном из перечисленных классов:
$ types_cmp.py -1 int str
__abs__ . . . . . int . .
__and__. . . . . .int. . .
__bool__. . . . . int . .
__ceil__ . . . . .int. . .
__contains__. . . . . .str
__divmod__ . . . .int. . .
...
Вывести методы, которые присутствуют строго во всех из перечисленных классов:
$ types_cmp.py -N int list dict
__class__ . . . . int .list .dict
__delattr__. . . .int. list. dict
__doc__ . . . . . int .list .dict
__eq__ . . . . . .int. list. dict
__format__. . . . int .list .dict
...
Вывести все методы с описаниями:
$ types_cmp.py -d dict
===========================================================
__class__ . . . . dict
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
type(object) -> the object's type
type(name, bases, dict) -> a new type
===========================================================
__contains__ . . .dict
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
D.__contains__(k) -> True if D has a key k, else False
...
Ну и конечно не забывайте про прямую проверку типов. В каких-то случаях она предпочтительнее:
if type(x) == str:
print('It is string')
Мне приходится сталкиваться с большими массивами неподдерживаемого кода, в котором надо разбираться. В конце концов я написал такой модуль:
import inspect
class magic_object:
def __init__(o, c, f, a, k):
o.h = c(*a, **k)
o.f = f
o.f("%s.__init__(*%s, **%s)" % (id(o.h), repr(a), repr(k)))
def __getattr__(o, name):
def d(*a, **k):
r = getattr(o.h, name)(*a, **k)
o.f("%s.%s(*%s, **%s) -> %s" % (id(o.h), name, repr(a), repr(k), repr(r)))
return r
return d
class magic_class:
def __init__(o, c, f):
o.c = c
o.f = f
def __call__(o, *a, **k):
return magic_object(o.c, o.f, a, k)
def magic_printing_func(x):
print "\033[44;34;1m*\033[0m %s" % x
def make_magic(the_class, printing_func=None):
if printing_func is None:
printing_func = magic_printing_func
# globals()[the_class.__name__] = magic_class(the_class, printing_func)
inspect.currentframe().f_back.f_globals[the_class.__name__] = magic_class(
the_class, printing_func
)
Пользоваться очень просто. Делаете из этого модуль, подключаете его и вызываете для любого класса магию. После этого всё, что происходит с объектами этого класса будет протоколироваться.
# coding: utf-8
from xxxx import make_magic
class T:
def a(o, x, zoom):
return 'ok'
# запускаем магию
make_magic(T) # <--- вот оно
# дальше весь код оставляем без изменений, магия работает
t = T()
t.a(1, zoom=9)
Вы получите подсвеченную отладку:
* 140015364812672.__init__(*(), **{})
* 140015364812672.a(*(1,), **{'zoom': 9}) -> 'ok'